# # add_file "tests/README" # # add_file "tests/t_add_vs_commit.at" # # add_file "tests/t_cvsimport2.at" # # add_file "tests/t_lf_crlf.at" # # add_file "tests/t_override_author_date.at" # # add_file "tests/t_rcs_import.at" # # add_file "tests/t_rename_dir_add_dir_with_old_name.at" # # add_file "tests/t_update_nonexistent.at" # # patch ".mt-attrs" # from [f9b65d9f157beb7932b20e4a85eb65487949ade9] # to [d916e2d789f2c0f4e92f983099b16ec904a2379b] # # patch "AUTHORS" # from [97910e402895c8bbae9ad72fad2e58c9f8965508] # to [e3730a36bbd3ebd44b05f6d93750bb83022d5572] # # patch "ChangeLog" # from [ae276c04af2b010374e324a49ddc03a5ab1af41e] # to [e490fd28c27b7d4735dfbfc5f5a1a253d0867257] # # patch "app_state.cc" # from [63120a266ad19ebd72022cf172ccbd0c299aa413] # to [b821fb66100e7626444a2f1e4bc2af4d572880b1] # # patch "app_state.hh" # from [9cfdb7a5976dc31edda11e99ee74046fdc318469] # to [27b58d6683bc026b41c07308738952067bf82926] # # patch "cert.cc" # from [451241f5ac6f41b70211dc92aa500e36688579af] # to [07be077e4c0d53abd9cac0bbdf201e808cf221a5] # # patch "cert.hh" # from [4b8178c3e7303d3465932f7d44039e8315f850a6] # to [e2b1d86c8f2610e854afed7ab661c4c2554e7004] # # patch "commands.cc" # from [3631712a17c33704a410a734fe2492c899b8ba6e] # to [82e7eeb431c5bd765fd43da20f96c28b2b9b4814] # # patch "contrib/README" # from [6d1db875fa3a286389a8c19eee3b19bf1772a3d6] # to [41748f8afac99a87841c3f94004bbfc6f4295611] # # patch "database.cc" # from [ab5914166d2a27c9c3f04f18594cc600e3c95f00] # to [5d62241bcc64569576fd10f45db8bf559d8c1769] # # patch "database_check.cc" # from [56b4ee811e023ae71548557652e1da4410429ffd] # to [924b949941d72064a292451e72c28bfb2e80755c] # # patch "monotone.1" # from [7ce55a7b2b6ec659e94edd7947ee9ce6c62053e1] # to [33e5e256e415dd185535ac1331d44a9de3f243cc] # # patch "monotone.cc" # from [2419f27fdb3cba77c658c0f4eac4d0b5026e1884] # to [daff288cbe075dc65c3dfd45e89ea3e71d438ed8] # # patch "monotone.texi" # from [82e309cffe8832da1e871c00c9795af49531f1df] # to [939f56de6aac68a630492031939ce4654f093203] # # patch "netsync.cc" # from [af29d63f695bfb5b0ade7e9d50e098773266f211] # to [6c6cd98bcb3fe5a9c3c45af45cc47074f9e77fb8] # # patch "tests/README" # from [] # to [fdbb3d9f63642092343e0ea58b7ee937f910103a] # # patch "tests/t_add_vs_commit.at" # from [] # to [7fd4b57e97609427e699e0cf3cca5c984ffd1330] # # patch "tests/t_cvsimport2.at" # from [] # to [4641874ff2fbedf55b84c1169dd86e4d2354c36b] # # patch "tests/t_diff_binary.at" # from [651f781bf58848169446baee444f3f1418b7b24f] # to [de45d9dca34e5765bd998968752d25368c8238e1] # # patch "tests/t_lf_crlf.at" # from [] # to [5c7f37f18e1ae4e195a4f7581145705d390e1747] # # patch "tests/t_netsync_defaults.at" # from [8f37b7de81c532b83851011586762f8c7fd91083] # to [09eba929e451e94f6075bd99fe75fc0469ba84e1] # # patch "tests/t_netsync_single.at" # from [1fa271a852629b392339705a3b6d5e143b7948c3] # to [faa5253849ae86d140b67fb93609d191456b0ec3] # # patch "tests/t_no_rename_overwrite.at" # from [345db00bfc31ac8c23f0735fe890c4d869e37448] # to [1fe86d8eeda1180521602e9b66628aadad9b75ac] # # patch "tests/t_override_author_date.at" # from [] # to [0f0499f19e887a4dbe83663f5e704110ca270bb3] # # patch "tests/t_rcs_import.at" # from [] # to [a77bf74fb559cc91d3167022f6595e2fb471bac4] # # patch "tests/t_rename_dir_add_dir_with_old_name.at" # from [] # to [b005c1839d019fa629d02fa1373f391715937594] # # patch "tests/t_update_nonexistent.at" # from [] # to [a7f5255b645f8be25c40d15a62f9f5279bf2aa59] # # patch "testsuite.at" # from [14b8600c48fdafc19eba6942e2270738b4bd8c71] # to [63f222bf1549f1b5ea773c38860809fd131a88e4] # # patch "work.cc" # from [2edb3fc960fee8c34b1abb13dff648ec63eeb40f] # to [dd1b1800d78f63c9f5615622d7c638c01c2f7459] # --- .mt-attrs +++ .mt-attrs @@ -1,4 +1,4 @@ - file "contrib/Notify.pl" + file "contrib/monotone-notify.pl" execute "true" file "contrib/ciabot_monotone.py" --- AUTHORS +++ AUTHORS @@ -52,6 +52,8 @@ Jon Bright Corey Halpin Jeremy Cowgar + Martin Dvorak + Emile Snyder supporting files: --- ChangeLog +++ ChangeLog @@ -1,8 +1,146 @@ 2005-04-17 Matt Johnston * Move base64 code as close to the database as possible, to avoid unnecessary inflating and deflating. +2005-04-17 Matt Johnston + + * commands.cc: warn that dropkey won't truly erase the privkey + from the database + * monotone.texi: same + +2005-04-17 Matt Johnston + + * database.cc: mention that it could be the filesystem that + is full in the SQLITE_FULL error message + +2005-04-16 Derek Scherger + + * work.cc (known_preimage_path): rename to... + (known_path): this, since it's image agnostic + (build_deletions): update for renamed function + (build_rename): ensure rename source exists in current revision + and rename target does not exist in current revision + + * tests/t_no_rename_overwrite.at: un-XFAIL + +2005-04-16 Nathaniel Smith + + * app_state.{cc,hh} (set_author, set_date): New methods. + * cert.cc (cert_revision_date): Rename to... + (cert_revision_date_time): ...an overloaded version of this. + (cert_revision_author_default): Check app.date. + * cert.hh: Expose cert_revision_date_time. + * commands.cc (commit): Handle --date. + * main.cc: Parse --date and --author options. + * monotone.1: Document --date, --author. + * monotone.texi (Working Copy, OPTIONS): Likewise. + + * tests/t_override_author_date.at: New test. + * testsuite.at: Add it. + + This commit heavily based on a patch by Markus Schiltknecht + . + +2005-04-16 Nathaniel Smith + + * ChangeLog: Fixup after merge. + +2005-04-17 Matthew Gregan + + * monotone.cc: Fix warnings: add missing initializers. + * netsync.cc: Fix warnings: inline static vs static inline. + +2005-04-16 Nathaniel Smith + + * tests/t_update_nonexistent.at: New test. + * testsuite.at: Add it. + + * commands.cc (update): Verify that user's requested revision + exists. + +2005-04-16 Nathaniel Smith + + * ChangeLog: Fixup after merge. + +2005-04-16 Emile Snyder + + * tests/t_add_vs_commit.at: New test for failing case. If you + add a file in you working dir, someone else adds the same file + and commits, then you do an update it messes up your working + directory. + * testsuite.at: Add it. + +2005-04-16 Nathaniel Smith + + * commands.cc (checkout): Move check for existence of revision + earlier. + + * tests/t_netsync_defaults.at, tests/t_netsync_single.at: + Don't hard-code netsync port. + +2005-04-16 Nathaniel Smith + + * testsuite.at: Use a random server port. + + * .mt-attrs, contrib/README: Update for Notify.pl -> + monotone-notify.pl rename. + + * monotone.1: Warn people off rcs_import. + * monotone.texi (Commands): Likewise. + +2005-04-16 Nathaniel Smith + + * AUTHORS: Add Emile Snyder . + +2005-04-16 Nathaniel Smith + + * tests/t_lf_crlf.at: New test from Emile Snyder + , with tweaks. + * testsuite.at: Add it. + +2005-04-16 Nathaniel Smith + + * ChangeLog: Small fixups. + +2005-04-16 Sebastian Spaeth + + * tests/t_cvsimport2.at: new test; CVS Attic files fail test + reported by: address@hidden 15.04.2005 02:45 + +2005-04-16 Sebastian Spaeth + + * tests/t_rcs_import.at: new test; problematic CVS import as + reported in the list. However it works just fine here, so it + really tests for a successful pass + +2005-04-16 Sebastian Spaeth + + * tests/README: new file, on how to create/run tests + +2005-04-16 Nathaniel Smith + + * tests/t_rename_dir_add_dir_with_old_name.at: XFAIL. + +2005-04-16 Nathaniel Smith + + * tests/t_diff_binary.at: Un-XFAIL. + +2005-04-16 Nathaniel Smith + + * monotone.texi (Network Service): Rewrite to include former + Exchanging Keys section. + (Branching and Merging): New tutorial section, inspired by a patch + from Martin Kihlgren . + (CVS Phrasebook): Add "Importing a New Project". + + * AUTHORS: Add Martin Dvorak. + +2005-04-15 Martin Dvorak + + * tests/t_rename_dir_add_dir_with_old_name.at: New test. + * testsuite.at: Add it. + 2005-04-16 Matt Johnston * change_set.cc (compose_rearrangement): remove logging statements @@ -2771,7 +2909,7 @@ * AUTHORS: Mention Wojciech and Neil. * revision.cc (calculate_ancestors_from_graph): Make non-recursive. -2005-01-17 Wojciech Miłkowski +2005-01-17 Wojciech Miłkowski * std_hooks.lua: Teach about meld. --- app_state.cc +++ app_state.cc @@ -273,6 +273,18 @@ } void +app_state::set_date(utf8 const & d) +{ + date = d; +} + +void +app_state::set_author(utf8 const & a) +{ + author = a; +} + +void app_state::set_depth(long d) { N(d > 0, --- app_state.hh +++ app_state.hh @@ -33,6 +33,8 @@ bool rcfiles; options_map options; utf8 message; + utf8 date; + utf8 author; utf8 search_root; std::vector revision_selectors; std::vector extra_rcfiles; @@ -62,6 +64,8 @@ void set_signing_key(utf8 const & key); void set_root(utf8 const & root); void set_message(utf8 const & message); + void set_date(utf8 const & date); + void set_author(utf8 const & author); void set_depth(long depth); void add_revision(utf8 const & selector); --- cert.cc +++ cert.cc @@ -566,11 +566,11 @@ string const testresult_cert_name = "testresult"; -static void -cert_revision_date(revision_id const & m, - boost::posix_time::ptime t, - app_state & app, - packet_consumer & pc) +void +cert_revision_date_time(revision_id const & m, + boost::posix_time::ptime t, + app_state & app, + packet_consumer & pc) { string val = boost::posix_time::to_iso_extended_string(t); put_simple_revision_cert(m, date_cert_name, val, app, pc); @@ -585,7 +585,7 @@ // make sure you do all your CVS conversions by 2038! boost::posix_time::ptime tmp(boost::gregorian::date(1970,1,1), boost::posix_time::seconds(static_cast(t))); - cert_revision_date(m, tmp, app, pc); + cert_revision_date_time(m, tmp, app, pc); } void @@ -593,7 +593,7 @@ app_state & app, packet_consumer & pc) { - cert_revision_date(m, boost::posix_time::second_clock::universal_time(), app, pc); + cert_revision_date_time(m, boost::posix_time::second_clock::universal_time(), app, pc); } void @@ -620,8 +620,7 @@ % app.branch_name); author = key(); } - put_simple_revision_cert(m, author_cert_name, - author, app, pc); + cert_revision_author(m, author, app, pc); } void --- cert.hh +++ cert.hh @@ -12,6 +12,7 @@ #include #include #include +#include // certs associate an opaque name/value pair with a particular identifier in // the system (eg. a manifest or file id) and are accompanied by an RSA @@ -119,6 +120,12 @@ void cert_revision_date_time(revision_id const & m, + boost::posix_time::ptime t, + app_state & app, + packet_consumer & pc); + +void +cert_revision_date_time(revision_id const & m, time_t time, app_state & app, packet_consumer & pc); --- commands.cc +++ commands.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include "commands.hh" #include "constants.hh" @@ -1183,7 +1184,10 @@ if (app.db.private_key_exists(ident)) { - P(F("dropping private key '%s' from database\n") % ident); + P(F("dropping private key '%s' from database\n\n") % ident); + W(F("the private key data may not have been erased from the")); + W(F("database. it is recommended that you use 'db dump' and")); + W(F("'db load' to be sure.")); app.db.delete_private_key(ident); key_deleted = true; } @@ -1777,6 +1781,9 @@ dir = idx(args, 1)(); complete(app, idx(args, 0)(), ident); + N(app.db.revision_exists(ident), + F("no revision %s found in database") % ident); + { cert_value b; guess_branch(ident, app, b); @@ -1808,9 +1815,6 @@ manifest_id mid; manifest_map m; - N(app.db.revision_exists(ident), - F("no revision %s found in database") % ident); - app.db.get_revision_manifest(ident, mid); put_revision_id(ident); @@ -2525,6 +2529,33 @@ else throw usage(name); } + +static boost::posix_time::ptime +string_to_datetime(std::string const & s) +{ + try + { + // boost::posix_time is lame: it can parse "basic" ISO times, of the + // form 20000101T120000, but not "extended" ISO times, of the form + // 2000-01-01T12:00:00. So do something stupid to convert one to the + // other. + std::string tmp = s; + std::string::size_type pos = 0; + while ((pos = tmp.find_first_of("-:")) != string::npos) + tmp.erase(pos, 1); + return boost::posix_time::from_iso_string(tmp); + } + catch (std::out_of_range &e) + { + N(false, F("failed to parse date string '%s': %s") % s % e.what()); + } + catch (std::exception &) + { + N(false, F("failed to parse date string '%s'") % s); + } + I(false); +} + CMD(commit, "working copy", "[--message=STRING] [PATH]...", "commit working copy to database") { @@ -2661,8 +2692,14 @@ dbw.consume_revision_data(rid, rdat); cert_revision_in_branch(rid, branchname, app, dbw); - cert_revision_date_now(rid, app, dbw); - cert_revision_author_default(rid, app, dbw); + if (app.date().length() > 0) + cert_revision_date_time(rid, string_to_datetime(app.date()), app, dbw); + else + cert_revision_date_now(rid, app, dbw); + if (app.author().length() > 0) + cert_revision_author(rid, app.author(), app, dbw); + else + cert_revision_author_default(rid, app, dbw); cert_revision_changelog(rid, log_message, app, dbw); } @@ -3122,7 +3159,11 @@ r_chosen_id = *(candidates.begin()); } else - complete(app, idx(args, 0)(), r_chosen_id); + { + complete(app, idx(args, 0)(), r_chosen_id); + N(app.db.revision_exists(r_chosen_id), + F("no revision %s found in database") % r_chosen_id); + } if (r_old_id == r_chosen_id) { --- contrib/README +++ contrib/README @@ -5,8 +5,8 @@ -- Log2Gxl.java: Java code to convert output from 'monotone log' into GXL, an XML-based graph description language. - -- Notify.pl: a Perl hack to create email logs with recent changes - in a repository database. It's designed to be run at regular + -- monotone-notify.pl: a Perl hack to create email logs with recent + changes in a repository database. It's designed to be run at regular intervals, for example from a cron script. It uses database variables (those handled with 'monotone set/unset') in the domain domain 'notify' to keep track of the last revisions that have --- database.cc +++ database.cc @@ -589,7 +589,7 @@ break; case SQLITE_FULL: - throw oops("Insertion failed because database is full"); + throw oops("Insertion failed because database (or filesystem) is full"); break; case SQLITE_CANTOPEN: --- database_check.cc +++ database_check.cc @@ -105,6 +105,8 @@ i != files.end(); ++i) { L(F("checking file %s\n") % *i); + file_data data; + app.db.get_file_version(*i, data); checked_files[*i].found = true; ++ticks; } @@ -128,8 +130,22 @@ i != manifests.end(); ++i) { L(F("checking manifest %s\n") % *i); + manifest_data data; + app.db.get_manifest_version(*i, data); checked_manifests[*i].found = true; + manifest_map man; + read_manifest_map(data, man); + + for (manifest_map::const_iterator entry = man.begin(); entry != man.end(); + ++entry) + { + checked_files[manifest_entry_id(entry)].manifest_refs++; + + if (!checked_files[manifest_entry_id(entry)].found) + checked_manifests[*i].missing_files++; + } + ++ticks; } @@ -152,7 +168,50 @@ i != revisions.end(); ++i) { L(F("checking revision %s\n") % *i); + revision_data data; + app.db.get_revision(*i, data); checked_revisions[*i].found = true; + + revision_set rev; + read_revision_set(data, rev); + + checked_manifests[rev.new_manifest].revision_refs++; + + if (!checked_manifests[rev.new_manifest].found) + checked_revisions[*i].missing_manifests++; + + if (checked_manifests[rev.new_manifest].missing_files > 0) + checked_revisions[*i].incomplete_manifests++; + + for (edge_map::const_iterator edge = rev.edges.begin(); + edge != rev.edges.end(); ++edge) + { + // ignore [] -> [...] manifests + + if (!null_id(edge_old_manifest(edge))) + { + checked_manifests[edge_old_manifest(edge)].revision_refs++; + + if (!checked_manifests[edge_old_manifest(edge)].found) + checked_revisions[*i].missing_manifests++; + + if (checked_manifests[edge_old_manifest(edge)].missing_files > 0) + checked_revisions[*i].incomplete_manifests++; + } + + // ignore [] -> [...] revisions + + // delay checking parents until we've processed all revisions + if (!null_id(edge_old_revision(edge))) + { + checked_revisions[edge_old_revision(edge)].revision_refs++; + checked_revisions[*i].parents.insert(edge_old_revision(edge)); + } + + // also check that change_sets applied to old manifests == new + // manifests (which might be a merge) + } + ++ticks; } --- monotone.1 +++ monotone.1 @@ -114,7 +114,8 @@ .TP \fBrcs_import\fP \fI ...\fP Import all file versions in RCS files. Does not reconstruct revisions -across the entire tree. +across the entire tree. You do not want this command, it is for +debugging; use cvs_import. .TP \fBcheckout\fP \fI[manifest-id]\fP \fI\fP An alias for \fB--message=\fI\fP .TP +\fB--author=\fI\fP +Use the given author as the value of the "author" cert when committing +a new revision, rather than the default author. Useful when +committing a patch on behalf of someone else, or when importing +history from another version control system. +.TP +\fB--date=\fI\fP +Use the given given date and time as value of the "date" cert when +committing a new revision, rather than the current time. Useful when +importing history from another version control system. +.TP \fB--root=\fI\fP Stop the search for a working copy (containing the @file{MT} directory) at the specified root directory rather than at the physical root of the --- monotone.cc +++ monotone.cc @@ -45,6 +45,8 @@ #define OPT_ROOT 16 #define OPT_DEPTH 17 #define OPT_ARGFILE 18 +#define OPT_DATE 19 +#define OPT_AUTHOR 20 // main option processing and exception handling code @@ -70,10 +72,12 @@ {"ticker", 0, POPT_ARG_STRING, &argstr, OPT_TICKER, "set ticker style (count|dot|none) [count]", NULL}, {"revision", 'r', POPT_ARG_STRING, &argstr, OPT_REVISION, "select revision id for operation", NULL}, {"message", 'm', POPT_ARG_STRING, &argstr, OPT_MESSAGE, "set commit changelog message", NULL}, + {"date", 0, POPT_ARG_STRING, &argstr, OPT_DATE, "override date/time for commit", NULL}, + {"author", 0, POPT_ARG_STRING, &argstr, OPT_AUTHOR, "override author for commit", NULL}, {"root", 0, POPT_ARG_STRING, &argstr, OPT_ROOT, "limit search for working copy to specified root", NULL}, {"depth", 0, POPT_ARG_LONG, &arglong, OPT_DEPTH, "limit the log output to the given number of entries", NULL}, {"xargs", '@', POPT_ARG_STRING, &argstr, OPT_ARGFILE, "insert command line arguments taken from the given file", NULL}, - { NULL, 0, 0, NULL, 0 } + { NULL, 0, 0, NULL, 0, NULL, NULL } }; // there are 3 variables which serve as roots for our system. @@ -185,8 +189,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)); } else { @@ -324,6 +328,14 @@ app.set_message(string(argstr)); break; + case OPT_DATE: + app.set_date(string(argstr)); + break; + + case OPT_AUTHOR: + app.set_author(string(argstr)); + break; + case OPT_ROOT: app.set_root(string(argstr)); break; @@ -334,7 +346,7 @@ case OPT_ARGFILE: sub_argvs.push_back(my_poptStuffArgFile(ctx(), - utf8(string(argstr)))); + utf8(string(argstr)))); break; case OPT_HELP: --- monotone.texi +++ monotone.texi @@ -212,11 +212,11 @@ @end ifnotinfo Version control systems, such as monotone, are principally concerned -with the storage and management of @i{multiple} versions of some -files. One way to store multiple versions of a file is, literally, to -save a separate @i{complete} copy of the file, every time you make a +with the storage and management of @i{multiple} versions of some files. +One way to store multiple versions of a file is, literally, to save a +separate @i{complete} copy of the file, every time you make a change. When necessary, monotone will save complete copies of your -files in their, compressed with the @command{zlib} compression format. +files, compressed with the @command{zlib} compression format. @ifinfo @smallexample @@ -1071,13 +1071,13 @@ @menu * Creating a Database:: * Generating Keys:: -* Exchanging Keys:: * Starting a New Project:: * Adding Files:: * Committing Work:: * Network Service:: * Making Changes:: * Dealing with a Fork:: +* Branching and Merging:: @end menu @@ -1221,82 +1221,10 @@ Abe and Beth do the same, with their secret passphrases. @page address@hidden Exchanging Keys address@hidden Exchanging Keys - -Jim, Abe and Beth all wish to work with one another, and trust one -another. For monotone to accept this situation, the team members will -need to exchange the public parts of their @sc{rsa} key with each -other. - -First, Jim exports his public key: - address@hidden address@hidden -$ monotone --db=~/jim.db pubkey jim@@juicebot.co.jp >~/jim.pubkey address@hidden group address@hidden smallexample - -His public key is just a plain block of ASCII text: - address@hidden address@hidden -$ cat ~/jim.pubkey -[pubkey jim@@juicebot.co.jp] -MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCbaVff9SF78FiB/1nUdmjbU/TtPyQqe/fW -CDg7hSg1yY/hWgClXE9FI0bHtjPMIx1kBOig09AkCT7tBXM9z6iGWxTBhSR7D/qsJQGPorOD -DO7xovIHthMbZZ9FnvyB/BCyiibdWgGT0Gtq94OKdvCRNuT59e5v9L4pBkvajb+IzQIBEQ== -[end] address@hidden group address@hidden smallexample - -Abe also exports his public key: - address@hidden address@hidden -$ monotone --db=~/abe.db pubkey abe@@juicebot.co.jp >~/abe.pubkey address@hidden group address@hidden smallexample - -As does Beth: - address@hidden address@hidden -$ monotone --db=~/beth.db pubkey beth@@juicebot.co.jp >~/beth.pubkey address@hidden group address@hidden smallexample - -Then all three team members exchange keys. The keys are not secret, -but the team members must be relatively certain that they are -communicating with the person they intend to trust, when exchanging -keys, and not some malicious person pretending to be a team -member. Key exchange may involve sending keys over an encrypted -medium, or meeting in person to exchange physical copies, or any -number of techniques. All that matters, ultimately, is for each team -member to receive the keys of the others. - -So eventually, after key exchange, Jim has Beth's and Abe's public key -files in his home directory, along with his own. He tells monotone to -read the associated key packets into his database: - address@hidden address@hidden -$ monotone --db=~/jim.db read <~/abe.pubkey -monotone: read 1 packet -$ monotone --db=~/jim.db read <~/beth.pubkey -monotone: read 1 packet address@hidden group address@hidden smallexample - -Beth and Abe similarly tell monotone to read read the two new public -keys they received into their respective databases. - - address@hidden @node Starting a New Project @section Starting a New Project -Before they can begin work on the project, Jim needs to create a +Before he can begin work on the project, Jim needs to create a @i{working copy} --- a directory whose contents monotone will keep track of. Often, one works on projects that someone else has started, and creates working copies with the @code{checkout} command, which you'll @@ -1529,10 +1457,7 @@ @smallexample @group $ monotone --db=jim.db --branch=jp.co.juicebot.jb7 commit --message='initial checkin of project' -monotone: beginning commit -monotone: manifest 2098eddbe833046174de28172a813150a6cbda7b -monotone: revision 2e24d49a48adf9acf3a1b6391a080008cbef9c21 -monotone: branch jp.co.juicebot.jb7 +monotone: beginning commit on branch 'jp.co.juicebot.jb7' monotone: committed revision 2e24d49a48adf9acf3a1b6391a080008cbef9c21 @end group @end smallexample @@ -1643,12 +1568,68 @@ @section Network Service Jim now decides he will make his base revision available to his -employees. To do this first adds a small amount of extra information -to his @file{.monotonerc} file, permitting Abe and Beth to access his -database: +employees. To do this he gives Abe and Beth permission to access his +database. There are two parts to this: first, he has to get a copy of +each of their public keys; then, he has to tell monotone that the +holders of those keys are permitted to access his database. +First, Abe exports his public key: + @smallexample @group +$ monotone --db=~/abe.db pubkey abe@@juicebot.co.jp >~/abe.pubkey address@hidden group address@hidden smallexample + +His public key is just a plain block of ASCII text: + address@hidden address@hidden +$ cat ~/abe.pubkey +[pubkey abe@@juicebot.co.jp] +MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCbaVff9SF78FiB/1nUdmjbU/TtPyQqe/fW +CDg7hSg1yY/hWgClXE9FI0bHtjPMIx1kBOig09AkCT7tBXM9z6iGWxTBhSR7D/qsJQGPorOD +DO7xovIHthMbZZ9FnvyB/BCyiibdWgGT0Gtq94OKdvCRNuT59e5v9L4pBkvajb+IzQIBEQ== +[end] address@hidden group address@hidden smallexample + +Beth also exports her public key: + address@hidden address@hidden +$ monotone --db=~/beth.db pubkey beth@@juicebot.co.jp >~/beth.pubkey address@hidden group address@hidden smallexample + +Then Abe and Beth both send their keys to Jim. The keys are not secret, +but the team members must be relatively certain that they are +communicating with the person they intend to trust, when exchanging +keys, and not some malicious person pretending to be a team +member. Key exchange may involve sending keys over an encrypted +medium, or meeting in person to exchange physical copies, or any +number of techniques. All that matters, ultimately, is that Jim receive +both Abe and Beth's key. + +So eventually, after key exchange, Jim has the public key files in his +home directory. He tells monotone to read the associated key packets +into his database: + address@hidden address@hidden +$ monotone --db=~/jim.db read <~/abe.pubkey +monotone: read 1 packet +$ monotone --db=~/jim.db read <~/beth.pubkey +monotone: read 1 packet address@hidden group address@hidden smallexample + +Now Jim's monotone is able to identify Beth and Abe, and he is ready to +give them permission to access his database. He does this by adding a +small amount of extra information to his @file{.monotonerc} file: + address@hidden address@hidden $ cat >>~/.monotonerc function get_netsync_read_permitted (collection, identity) if (identity == "abe@@juicebot.co.jp") then return true end @@ -1719,8 +1700,9 @@ always running; this way, everyone always knows where to go to get the latest changes, and people can push their changes out without first calling their friends and making sure that they have their servers -running. To support this style of working, monotone remembers the first -server you use, and makes that the default for future operations. +running. To make this style of working more convenient, monotone +remembers the first server you use, and makes that the default for +future operations. @page @node Making Changes @@ -1785,10 +1767,8 @@ @smallexample @group $ monotone commit -monotone: beginning commit -monotone: manifest b33cb337dccf21d6673f462d677a6010b60699d1 -monotone: revision 70decb4b31a8227a629c0e364495286c5c75f979 -monotone: branch jp.co.juicebot.jb7 +monotone: beginning commit on branch 'jp.co.juicebot.jb7' +monotone: commited revision 70decb4b31a8227a629c0e364495286c5c75f979 @end group @end smallexample @@ -1894,10 +1874,7 @@ @smallexample @group $ monotone commit -monotone: beginning commit -monotone: manifest eaebc3c558d9e30db6616ef543595a5a64cc6d5f -monotone: revision 80ef9c9d251d39074d37e72abf4897e0bbae1cfb -monotone: branch jp.co.juicebot.jb7 +monotone: beginning commit on branch 'jp.co.juicebot.jb7' monotone: committed revision 80ef9c9d251d39074d37e72abf4897e0bbae1cfb @end group @end smallexample @@ -2012,10 +1989,7 @@ @smallexample @group $ monotone commit --message='interrupt implementation of src/banana.c' -monotone: beginning commit -monotone: manifest de81e46acb24b2950effb18572d5166f83af3881 -monotone: revision 8b41b5399a564494993063287a737d26ede3dee4 -monotone: branch jp.co.juicebot.jb7 +monotone: beginning commit on branch 'jp.co.juicebot.jb7' monotone: committed revision 8b41b5399a564494993063287a737d26ede3dee4 @end group @end smallexample @@ -2126,6 +2100,95 @@ step) and your committed state is still safe. It is therefore recommended that you commit your work @emph{first}, before merging. address@hidden address@hidden Branching and Merging address@hidden Branching and Merging + +So by now you're familiar with making changes, sharing them with other +people, and integrating your changes with their changes. Sometimes, +though, you may want to make some changes, and @emph{not} integrate them +with other people's --- or at least not right away. One way to do this +would be to simply never run @command{monotone merge}; but it would +quickly become confusing to try and keep track of which changes were in +which revisions. This is where @emph{branches} are useful. + +Continuing our example, suppose that Jim is so impressed by Beth's work +on banana juice support that he assigns her to work on the JuiceBot 7's +surprise new feature: muffins. In the mean time, Abe will continue +working on the JuiceBot's basic juice-related function. + +The changes required to support muffins are somewhat complicated, and +Beth is worried that her work might destabilize the program, and +interfere with Abe's work. In fact, she isn't even sure her first +attempt will turn out to be the right approach; she might work on it for +a while and then decide it was a bad idea, and should be discarded. For +all these reasons, she decides that she will work on a branch, and then +once she is satisfied with the new code, she will merge back onto the +mainline. + +She decides that since main development is in branch address@hidden, she will use branch address@hidden So, she makes the first few edits to +the new muffins code, and commits it on a new branch by simply passing address@hidden to commit: + address@hidden address@hidden +$ monotone commit --branch=jp.co.juicebot.jb7.muffins --message='initial autobake framework' +monotone: beginning commit on branch 'jp.co.juicebot.jb7.muffins' +monotone: committed revision d33caefd61823ecbb605c39ffb84705dec449857 address@hidden group address@hidden smallexample + +That's all there is to it --- now there is a address@hidden branch, with her initial checkin on +it. She can make further checkins from the same working copy, and they +will automatically go to the muffins branch; if anyone else wants to +help her work on muffins, they can check out that branch as usual. + +Of course, while Beth is working on the new muffins code, Abe is still +making fixes to the main line. Occasionally, Beth wants to integrate +his latest work into the muffins branch, so that her version doesn't +fall too far behind. She does this by using the @command{propagate} +command: + address@hidden address@hidden +$ monotone propagate jp.co.juicebot.jb7 jp.co.juicebot.jb7.muffins +monotone: propagating jp.co.juicebot.jb7 -> jp.co.juicebot.jb7.muffins +monotone: [source] da003f115752ac6e4750b89aaca9dbba178ac80c +monotone: [target] d0e5c93bb61e5fd25a0dadf41426f209b73f40af +monotone: common ancestor 853b8c7ac5689181d4b958504adfb5d07fd959ab found address@hidden group address@hidden smallexample + +The @command{propagate} merges all of the new changes on one branch onto +another. + +When the muffins code is eventually stable and ready to be integrated +into the main line of development, she simple propagates the other way: + address@hidden address@hidden +$ monotone propagate jp.co.juicebot.jb7.muffins jp.co.juicebot.jb7 +monotone: propagating jp.co.juicebot.jb7 -> jp.co.juicebot.jb7.muffins +monotone: [source] 4e48e2c9a3d2ca8a708cb0cc545700544efb5021 +monotone: [target] bd29b2bfd07644ab370f50e0d68f26dcfd3bb4af +monotone: common ancestor 652b1035343281a0d2a5de79919f9a31a30c9028 found address@hidden group address@hidden smallexample + +Monotone always records the full history of all merges, and is designed +to handle an arbitrarily complicated graph of changes. You can make a +branch, then branch off from that branch, propagate changes between +arbitrary branches, and so on; monotone will track all of it, and do +something sensible for each merge. Of course, it is still probably a +good idea to come up with some organization of branches and a plan for +which should be merged to which other ones. Monotone may keep track of +graphs of arbitrary complexity; but, you will have more trouble. +Whatever arrangement of branches you come up with, though, monotone +should be able to handle it. + @node Advanced Uses @chapter Advanced Uses @@ -2942,7 +3005,7 @@ @tab @smallexample @group -$ monotone diff 3e7db 278df +$ monotone diff -r 3e7db -r 278df @end group @end smallexample @end multitable @@ -3024,6 +3087,29 @@ manifest of the current revision. address@hidden Importing a New Project + address@hidden @columnfractions .4 .4 address@hidden address@hidden address@hidden +$ cvs import wobbler vendor start address@hidden group address@hidden smallexample address@hidden address@hidden address@hidden +$ monotone --db=/path/to/database.db --branch=com.foo.wobbler setup . +$ monotone add . +$ monotone commit address@hidden group address@hidden smallexample address@hidden multitable + +The @command{setup} command turns an ordinary directory into a +monotone working copy. After that, you can add your files and commit +them as usual. + @heading Initializing a Repository @multitable @columnfractions .4 .4 @@ -3288,12 +3374,19 @@ @itemize @item An @code{author} cert, indicating the person responsible for the changes -leading to the new revision. +leading to the new revision. Normally this defaults to your signing key +or the return value of the @code{get_author} hook; you may override this +by passing the @option{--author} option to commit. This is useful when +committing a patch on behalf of someone else, or when importing ``by +hand'' from another version control system. @item A @code{branch} cert, indicating the branch the committed revision belongs to. @item A @code{date} cert, indicating when the new revision was created. +Normally this defaults to the current time; you may override this by +passing the @option{--date} option to commit. This is useful when +importing ``by hand'' from another version control system. @item A @code{changelog} cert, containing the ``log message'' for these changes. If you provided @var{logmsg} on the command line, this text @@ -3720,7 +3813,10 @@ This command drops the public and/or private key. If both exist, both are dropped, if only one exists, it is dropped. This command should be used with caution as changes are irreversible without a backup of -the key(s) that were dropped. +the key(s) that were dropped. Note also that the private key is not +guaranteed to actually be erased from your database file - if you are +going to make the database file public, you should use 'db dump' +and 'db load' to import into a fresh database. @item monotone chkeypass @var{id} @@ -5763,7 +5859,8 @@ @item @b{rcs_import} @i{ ...} Import all file versions in RCS files. Does not reconstruct revisions -across the entire tree. +across the entire tree. You do not want this command, it is for +debugging; use cvs_import. @comment TROFF INPUT: .TP @item @b{checkout} @i{[manifest-id]} @i{} @@ -5935,6 +6032,17 @@ applies to the commit command but it may also apply to the comment command in the future. address@hidden @address@hidden} +Use the given author as the value of the "author" cert when committing +a new revision, rather than the default author. Useful when +committing a patch on behalf of someone else, or when importing +history from another version control system. + address@hidden @address@hidden} +Use the given given date and time as value of the "date" cert when +committing a new revision, rather than the current time. Useful when +importing history from another version control system. + @item @address@hidden} Stop the search for a working copy (containing the @file{MT} directory) at the specified root directory rather than at the physical root of the --- netsync.cc +++ netsync.cc @@ -725,7 +725,7 @@ attached[i] = curr_attached; } -static inline id +inline static id plain_id(manifest_id const & i) { id tmp; @@ -734,7 +734,7 @@ return tmp; } -static inline id +inline static id plain_id(file_id const & i) { id tmp; --- tests/README +++ tests/README @@ -0,0 +1,48 @@ +HOWTO make tests +================ + +Quick and dirty howto, to get you up to create and run tests. +Very early draft. Feel free to improve. + +Running tests: +-------------- +- Starting in the monotone main dir. After having './configure'd monotone you + can do 'make testsuite' to create 'testsuite'. Running './testsuite' will + run all tests. +- 'testsuite -l' lists the names and numbers of all available tests +- 'testsuite ' runs only test number n +- option -v will show the command outputs +- option -d will keep the testsuite.dir files for post-test debugging +- option -h is your friend :) + +Creating tests: +--------------- +- Copy and paste is your friend :) +- TODO: need more here... + + +Template for a test (name t_.at +------------------- + +AT_SETUP([brief test description goes here]) +MONOTONE_SETUP + +#the next lines (including AT_XFAIL_IF) state that the test is +#expected to fail as this is still a bug. Remove if it should pass! +# This test is a bug report. It is expected to fail +AT_XFAIL_IF(true) + +#AT_CHECK executes a shell command, second argument is the error +#return code we expect, third argument is the output we expect from +#stdout. use ignore if you don't care about the output. If oyu use +#stdout all following commands can use file 'stdout' for further +#processing. Same goes with 'stderr' as the last argument +#see autoconf tutorials +#e.g. http://www.gnu.org/software/autoconf/manual/autoconf-2.57/ +# html_node/autoconf_167.html for further information. +AT_CHECK(MONOTONE import foo, [], ignore, ignore) +... +... +... +AT_CLEANUP +(END) --- tests/t_add_vs_commit.at +++ tests/t_add_vs_commit.at @@ -0,0 +1,47 @@ +AT_SETUP([add working copy commit in another]) +MONOTONE_SETUP + +# This test is a bug report +AT_XFAIL_IF(true) + +# 1. Alice writes a file, does an add, *doesn't* do a commit, and sends patch +# 2. Bob applies (modified) patch to tree, does the add, then a commit. +# 3. Now Alice does an update (resolves the merge conflict, choosing Bob's changes). +# +# Alice's working dir now give I()'s when she tries to do stuff (diff, update, etc.). + +AT_DATA(initial, [some initial data +]) + +AT_DATA(foo.alice, [foo +change me +bar +]) + +AT_DATA(foo.bob, [foo +me change +bar +]) + +# Alice does her add +AT_CHECK(mkdir alicewd) +AT_CHECK(cp initial alicewd/initial) +AT_CHECK(MONOTONE --branch=testbranch setup alicewd, [], [ignore], [ignore]) +AT_CHECK( (cd alicewd; MONOTONE --root=. add initial), [], [ignore], [ignore]) +AT_CHECK( (cd alicewd; MONOTONE --root=. commit -m 'initial commit'), [], [ignore], [ignore]) +AT_CHECK(cp foo.alice alicewd/foo) +AT_CHECK( (cd alicewd; MONOTONE add --root=. foo), [], [ignore], [ignore]) +# Note, alice does not commit this add... + +# Bob does add of same file, with edits, and commits +AT_CHECK(MONOTONE --branch=testbranch checkout bobwd, [], [ignore], [ignore]) +AT_CHECK(cp foo.bob bobwd/foo) +AT_CHECK( (cd bobwd; MONOTONE --root=. add foo), [], [ignore], [ignore]) +AT_CHECK( (cd bobwd; MONOTONE --root=. commit -m 'bob commit'), [], [ignore], [ignore]) +REV=`BASE_REVISION` + +# Alice does her update, then attempts, eg., a diff +AT_CHECK( (cd alicewd; MONOTONE --root=. update $REV), [], [ignore], [ignore]) +AT_CHECK( (cd alicewd; MONOTONE --root=. diff), [], [ignore], [ignore]) + +AT_CLEANUP --- tests/t_cvsimport2.at +++ tests/t_cvsimport2.at @@ -0,0 +1,41 @@ +AT_SETUP([test failing cvs import (Attic)]) +MONOTONE_SETUP + +# This test imports a cvs archive with files in the Attic which fails +#monotone: fatal: std::logic_error: change_set.cc:2546: invariant 'I(b.rearrangement.deleted_files.empty())' violated + +# reported by: address@hidden 15.04.2005 02:45 +# This test is a bug report. +AT_XFAIL_IF(true) + +AT_DATA(prepare.sh,[#!/bin/sh +export CVSROOT=$PWD/cvsroot + +cvs init +mkdir src +echo FOO > src/foo +( + cd src + cvs import -m import mod vtag rtag +) +rm -rf src + +mkdir src +( + cd src + cvs co mod + cd mod + cvs tag -b branch + cvs up -r branch + echo BAR > bar + cvs add bar + cvs ci -m 'add bar' +) +]) + +AT_CHECK(sh prepare.sh, [], ignore, ignore) + +AT_CHECK(MONOTONE --branch=test cvs_import ., [], ignore, ignore) + +AT_CLEANUP +(END) --- tests/t_diff_binary.at +++ tests/t_diff_binary.at @@ -1,10 +1,7 @@ AT_SETUP([diff a binary file]) MONOTONE_SETUP NEED_UNGZB64 -# This test is a bug report. -AT_XFAIL_IF(true) - # diff should probably not display the contents of binary files AT_DATA(binary.gz.b64, --- tests/t_lf_crlf.at +++ tests/t_lf_crlf.at @@ -0,0 +1,44 @@ +AT_SETUP([use get_linesep_conv hook]) +MONOTONE_SETUP +NEED_UNB64 + +# This test is a bug report. +AT_XFAIL_IF(true) + +# This test excercises the common case of wanting to do newline +# character conversion so that win32 users can have native line endings +# in their working copies. + + +# wrote files with 'foo\r\n' and 'foo\r\nfoo\r\n' and used mimencode +# to generate the following b64 encoded contents. +# +# Note the newline before the closing ']', it's necessary. +# +AT_DATA(foo.lfcr.b64, [Zm9vDQo= +]) +AT_DATA(foofoo.lfcr.b64, [Zm9vDQpmb28NCg== +]) + +UNB64(foo.lfcr.b64, foo.lfcr) +UNB64(foofoo.lfcr.b64, foofoo.lfcr) + +AT_DATA(linesep.lua, [ +function get_linesep_conv(name) + return {"LF", "CRLF"} +end +]) + +AT_CHECK(cp foo.lfcr foo, [], [ignore], [ignore]) +AT_CHECK(MONOTONE --rcfile=linesep.lua add foo, [], [ignore], [ignore]) +AT_CHECK(MONOTONE --rcfile=linesep.lua --branch=foo commit -m foo, [], [ignore], [ignore]) +FOO_REV=`BASE_REVISION` + +AT_CHECK(cp foofoo.lfcr foo, [], [ignore], [ignore]) +AT_CHECK(MONOTONE --rcfile=linesep.lua commit -m foofoo, [], [ignore], [ignore]) +FOO_FOO_REV=`BASE_REVISION` + +AT_CHECK(MONOTONE --rcfile=linesep.lua update $FOO_REV, [], [ignore], [ignore]) +AT_CHECK(cmp foo foo.lfcr, [], [ignore], [ignore]) + +AT_CLEANUP --- tests/t_netsync_defaults.at +++ tests/t_netsync_defaults.at @@ -35,7 +35,7 @@ AT_CHECK(test -f testdir2/testfile) # And finally, -AT_CHECK(MONOTONE2 set database default-server 127.0.0.1:5555, [], [ignore], [ignore]) +AT_CHECK(MONOTONE2 set database default-server 127.0.0.1:$_PORT, [], [ignore], [ignore]) AT_CHECK(MONOTONE2 set database default-collection thirdbranch, [], [ignore], [ignore]) AT_CHECK(MONOTONE2 sync, [], [ignore], [ignore]) AT_CHECK(MONOTONE2 checkout --branch=thirdbranch $THIRDBRANCH_R testdir3, [], [ignore], [ignore]) --- tests/t_netsync_single.at +++ tests/t_netsync_single.at @@ -24,9 +24,9 @@ VER0=`BASE_REVISION` NETSYNC_KILLHARD - MONOTONE --rcfile=netsync.lua serve 127.0.0.1:5555 testbranch & + MONOTONE --rcfile=netsync.lua serve 127.0.0.1:$_PORT testbranch & sleep 5 -AT_CHECK(MONOTONE --rcfile=netsync.lua --db=test2.db pull 127.0.0.1:5555 testbranch, [], [ignore], [ignore]) +AT_CHECK(MONOTONE --rcfile=netsync.lua --db=test2.db pull 127.0.0.1:$_PORT testbranch, [], [ignore], [ignore]) NETSYNC_KILLHARD AT_CHECK(MONOTONE --db=test2.db ls certs $VER0, [], [stdout]) --- tests/t_no_rename_overwrite.at +++ tests/t_no_rename_overwrite.at @@ -1,9 +1,6 @@ AT_SETUP([rename cannot overwrite files]) MONOTONE_SETUP -# This test is a bug report. -AT_XFAIL_IF(true) - # "rename" needs to check that it isn't overwriting existing # files/directories. @@ -19,19 +16,18 @@ ADD_FILE("rename_dir/file", [bar bar ]) -AT_CHECK(MONOTONE rename rename_file target_file, [3], [ignore], [ignore]) -AT_CHECK(MONOTONE rename rename_file target_dir, [3], [ignore], [ignore]) -AT_CHECK(MONOTONE rename rename_dir target_file, [3], [ignore], [ignore]) -AT_CHECK(MONOTONE rename rename_dir target_dir, [3], [ignore], [ignore]) +AT_CHECK(MONOTONE rename unknown_file other_file, [1], [ignore], [ignore]) +AT_CHECK(MONOTONE rename rename_file target_file, [1], [ignore], [ignore]) +AT_CHECK(MONOTONE rename rename_file target_dir, [1], [ignore], [ignore]) +AT_CHECK(MONOTONE rename rename_dir target_file, [1], [ignore], [ignore]) +AT_CHECK(MONOTONE rename rename_dir target_dir, [1], [ignore], [ignore]) COMMIT(testbranch) -AT_CHECK(MONOTONE rename rename_file target_file, [0], [ignore], [ignore]) -AT_CHECK(MONOTONE rename rename_file target_dir, [0], [ignore], [ignore]) -AT_CHECK(MONOTONE rename rename_dir target_file, [0], [ignore], [ignore]) -AT_CHECK(MONOTONE rename rename_dir target_dir, [0], [ignore], [ignore]) +AT_CHECK(MONOTONE rename unknown_file other_file, [1], [ignore], [ignore]) +AT_CHECK(MONOTONE rename rename_file target_file, [1], [ignore], [ignore]) +AT_CHECK(MONOTONE rename rename_file target_dir, [1], [ignore], [ignore]) +AT_CHECK(MONOTONE rename rename_dir target_file, [1], [ignore], [ignore]) +AT_CHECK(MONOTONE rename rename_dir target_dir, [1], [ignore], [ignore]) -# this should fail -COMMIT(testbranch) - AT_CLEANUP --- tests/t_override_author_date.at +++ tests/t_override_author_date.at @@ -0,0 +1,17 @@ +AT_SETUP([--author, --date]) +MONOTONE_SETUP + +ADD_FILE(testfile, [floooooo +]) +AT_CHECK(MONOTONE commit --author=the_author --date=1999-12-31T12:00:00 --branch=foo --message=foo, [], [ignore], [ignore]) +REV=`BASE_REVISION` +AT_CHECK(MONOTONE log $REV, [], [stdout], [ignore]) + +AT_CHECK(grep -q '^Author: the_author' stdout) +AT_CHECK(grep -q '^Date: 1999-12-31T12:00:00' stdout) + +SET_FILE(testfile, [oovel +]) +AT_CHECK(MONOTONE commit --date=1999-12-31T12:00foo --branch=foo --message=foo, [1], [ignore], [ignore]) + +AT_CLEANUP --- tests/t_rcs_import.at +++ tests/t_rcs_import.at @@ -0,0 +1,190 @@ +AT_SETUP([test problematic cvs import]) +MONOTONE_SETUP +NEED_UNGZB64 + +# This test imports a rcs file which fails according to the mailing list +# reporter: Carl Christian Kanne "Bug? in CVS import monotone 0.18" +# Date: Fri, 15 Apr 2005 12:53:13 +0200 +# However when I test it, it succeeds---> examine +# This test is a bug report. +#AT_XFAIL_IF(true) + +# This rcs file fails to be imported correctly by monotone + +AT_DATA(rcsfile.gz.b64, [ +H4sICKQRYUIAA2hhc2h0YWJsZS5oaCx2AMRce3PbNrb/2/wUqNvptR1b4lMvt13n4W29k8SZxG3v +bKfjoUXIYi2RWpKy4u7kfvY95wAgAYqipCY71ztVbAI8AM7zd86BdsrD6MDpuM65FY7HPM/Prfxp +fpfOcutgFkf5CMc6dse1DpKwiD+eubf2rX22yHgPhpyB8bj+BKf5+NCrPfTkw8eYrz7OZ/l4yuch +POvBSr51MImzvMj4OH3k2RM8DuBxzzq4ufxwc/nqNozC7CHMbl3bdhzb6dme08dJmyb4tmf32iZ4 +MKGVggtLDNsmONso2Fv2YA+3TRhsWcLub5sAjLIHbROCbRR8x/GctgkgCX8zBXvg4jG9tgmDig/h +3TJ/uo34I5/dznl2zxdpnBRrY1I/QG3ePr+5+t+/f7h9dfnm+va9Iwfc5qVAorYXbOYHngUmmKeZ +h0kWPqlx3/E8t42AZ/te0ELAs13fbhl3bdcbtIw7MD5sGbfb6YPSuYHbMj6A9zcrJWpL+wFhvL6B +GoEeEPBbCPS2EQiAgNdCIFhjUY2ADwRahAz/te7ABY1t4wGOt+7AdfutR8DxuhbUCPS2ENjCRNcN +NhyhhWawZVOkGm2LkuhbJ+CuNnsbmICia7E/F6XbvoS7jYKzph3GBHCHWya4frWH95e/XF3+2jbZ +dZw2/+k4Q2BL0Dah77gt0RBdrO27ftOEtpeC6qU7Pkkzfps/JWPxQPutCDP0z/Q/8NFpdCf+Ordm +6fghP2cQ1eNxcW6N0/mcJ8XBRbfLLs4ty0KUYUVhwQ9gRfDabscNOk7Q8Xsdd3h+EC6LaZqxJM1A +C89xoYKzy4+Lc+suCxNADwBbEv6xQCRjnxM52yTnDDtOvxPAL4O9yDlDIucMdXIAiPpIzgs6Xn8/ +cgNBblCS8zs2bc1xOr7X8Sty8/xuC62+oNXXaQ3wsEjR77j+HrR6glZPp9UH3iNFEIKzz74CQSuo +0QLeAyG3Ezh70PIFLV+n5aM0XRs/g95+7PcEOa8k53Ucm6Tpdzy34wd7bM0VtFyNFjDe9fGMoLra +MYuEL2Fv2zbnCIKOThCO6xHTeh1/T80VhuDYOjmg5ZEhOLp67EJO2MFQJwaKRkbqot7tRUxYQWUE +LqoZSjRAHdGkAJlBzGe8nZqwg75JDW3exnNq1HbZmjCEnk7MR2cEOhIMwOJ32pqFhDo+ej5JVthE +ZRKgdD2yB/Bxri7aFc+L7boizMI3ydmojR0PrKKy1vG4nZAwCE8n5JOOBOSR/D33JWxCmsRwiPux +xSeww9mTmLQHSWyAG3J7uDk4qFftDD/ygjcTQ0nIGERUBcnO55LVqZGgTbtAD+B3Ak/Xl3C6hZIV +8XxsXVyocDhL762LjCfhnEcQOcMEYnLE4oJnYYH7S9m0uJ2G+bQI72bcurAKIGRddE++zI9lMfb8 ++tWLs3dZ+gcfF/j3az4FniynMzZZ8oy9y8KHIsbsnV0lEzSuIn5gV1dXMPXnJIbsPY+LkBfsDch6 +yuM5PP+Row0+EXVizIh9eOQJ+4nPIMljcEp2E89m7FepIjjxm6toxMqTdqbT00eGIZ5hOO7abtcZ +MkA9mMsMpJEjk9k3lvWFmNG1rK/jSRLxCfvp+Yefbp6/eH1pfQ1/xgnXnsCkZDxbRpwdZkXejZNJ +FnbLjVe/3YU5HuPQskBaFjthN8BCHGU0zJY5z9l4luYgeXwcJ/cdmgPSn+csnYB2cna3HD/wImdh +xkE/AJVFSCpOWAhDkwnPxDsAtLIY6MFAoZaJ4gxEmmZPjJJqVCYco8ILEYF11AtimQ57HScPsBF6 +Bo4PAVzOVnExNebBOjmLUmDL3RNSChcLnkT4XijW4qS6PBxPa6vgjtlqGsMATczVrtBANmwKHnet +8SzMc/YTnOuGuDdii+XdLB5Xj14Av7/753t+f4o2o0yInvzAfmD/tizxxgi1jbHiacFR1Otz1Z/n +YmK5wBFy9bbAZyx8FWcf4j/5qXVAf7MlHMZzxdjb9HoClPLGwfc8X84K3KYaff7Lm9EIDPAeGHmV +5DwrcEl80DjldZo+LBc7THk5X2yc8TJdPG0enPEw+dl8+UMxL16+OKEjiN/LoXGa5AXLgRvInPDl +dJk8GLwRE5ZJHt8noOyzFBXl7XJ+x7PryQtKG9j3zD4+J37/X8Vw+YQ+HtMYHGMSF3E4A+JHKKsT +lqdz/nz5EbktJ4vnM+KAnPQnfL4IkwedXJzM0KyJasZzXrxcZuCHiyvQvyODVEwiOcr4fZyjYtNT +RWqRxY/g7kf0F9k5/pxURvgYzpZgcxgbhG6Dvt9xSRSNmeZ3S037heaTgk55pQ30WNt+bamx2DzY +FDjjOE02+IFomaGRCuZ0aAlFpQw5K3TMaTJ7ko84zMrS5f2Ukb2TSYJEZzOgCcTU+9FyAbaF05tc +kfDpxmFfAok4h72+BraORlXIm3JNFHhk69N56UNBULUZyNAQDwycBlmWHEBlC2EJcmZhIc56Qn5G +MoDNl6CWJHzaqdoC+RtSjFITR6N1HQGPAsHy+sfrF/+4fHmDG61t7Ht8gCTAV/xW/Yqm8XvnDtQp +QUX7BAEFneeEQZ5cRRmJEGyBEO55AntDvY9Mh1cigshxmGOF9LkpmEIEFcHU6dp9DKZeMPL6ZjCN +3D7Soc+9fG6Dw4082pMn9lS53I3+Vhwa8nA69Dx9xGgF6gjuM2X3WTjmf0DQOAVXEk9iju4AXp3A +YzIwyWLa2NkPlavYj0cD5JHftYddB3jgjHxv5PcxU5QMCt2AeaAiqExXb95dv795/vZmpHGJf1yA +aeSolCmERdjmu+evb68XUr8XWRotxwIFIQ3th0wvSQuBCqqZX331F8Qi+e9aYTBggeEswPcj8XuE +IMhE6Y1YLCBHuS4EeYjn8YKjq7zLePgAcMMwYi1qCI+l4oqMnWi1UqgDIdS8AEx8D4uEGWBe9KcJ +BQLcBsWJbIm+aj+Z9aXMBoATmT0cOf7I9XWZoShruC2c3V8vukr3CKiFCDEBovvEa/j06BDLHJ2I +wVzwV6V6nTeGJ13mEFLfSZ6esk1xCxYcygWJFiq+CkT0YAxROStDYhj4plQhNwmB7DKrrEHzvYbU +zL3BRLW7WoAJe8QPKcC+EOAZAL/xEoFhSH5WX4uWyq0zcKpglYRW2TxcQMqApiCc6wESEFqOekim +bbwP4XEcgmaCX0ANRBwJFgXg4ZHjyyI07aCptA2RWOFc2ATPhHAigcFQT0EJxRbCCQx/KPhCPt1P +AXtSAftdd8jswQg7KrrTiHwbXpeM7ClGalzCHb4JF2+AU9cap4AFSboSqQJOqYwec6g/MH6FqBx5 +FX8h8M7x17h4miEJgO45y6fpcoayeOBER0kDQiAgccjtwgUxLIwi2ExIupZAhFxIFikhl1I8q21n +CvsB0bN3pgxgM0XOZxPIE6QZhZX7QS7TBnnGdS06o8PdJTN09uWSlHD8D/CDI7tSVCI8Guwk4Stg +ZbHMEg1tUUAXbm2yTMakqpBSlTveT75BJV+XOSBcdxQ4unw90AAfjHKI/+yWMzRnDHo8aEsbtiYN +W1OGbQlDS7rQnixsTBW2JAr7pAlmkmDt5KQ/y0Vb2zILa81vm17b2iXnaM84rKgHAR2UdQD/DKwy +C9g1AJD7b3X+JUEZlMFiFJwXeYsoQZj5fEla01eBBt6ml+JtnXY5fQ08mHpMLNv+koE4DIZ8XlL0 +eSnR7gkRnWr3ZMg44a4ZJq2xPbuMBh66wkGgRf1ABSvpTNE1y/QJV9cDRIhcKr21MEjcZc7nMbny +9TrmTs7Xl87X71ICM3KGo6BXy1p8cMtWBEjXIbyL1O7SdLbRlKJ+APApdAAvBgPMLhGKf/M6vV/b +wDc48p4/knjEdhr3IzeEszFxARvJL/+1DGXygsVAJoA72FSlArnMJPQFPFrA6zo2pWn+yHNHfsAw +3ODUM4jXCKG19KesFmogDGYeqIBeOT0GmHuaRrIEB9OltoxBeKK0CC9Jr0c1xwVsGSFBriF2idjW +qMrXIz6DaZH2giDIJlk6B1UvQX4ujoOOViGOBna4kh2QkQGoh8jrBBh8y4Ybzp/EH2HBVZgloHRN +PHUUEZCbh0SC3sgf6EIzTRMxJ4EoMHrgAODd3EScCGAF6yrgySTqgTMZCAQNoURciF+I6wIyCRCz +vmFbbRj0wKPCt4M5jbZhhR6J+qS+fxENiNFLiDUjyWpO25CA05xzClKco0ME+uE9AvxTsnaNKCJL +XkJ/QRKUUPAElOQOs7txoWu7mZMKtYNAX4TAGoZXBFLM+yIuiH34RwUpASei1yS/W9pvjsXn1ZQn +a/i/QQiINMkfn1RcB4FR4doZOQit15cNFyB4nuv+G84cJyLbSVWyXJ4fvR6cA5Q9znPQbXKF9xAe +FshPCKL5NF6QKSFXIqSAW3/55t0ZHh85DBQLHsLQBElev391+V6NrWvGUCmG27XBUQegFSPb0GRp +81oPCaSCfRpu+oh12gOi7WIi7dpIG6Aueh7ZBqWSx4frs5fPnp2hxTXobb+iAK7VsVFtkUK1O/D7 +PMEN1jRUVOmQT1SVgIShiiXlUF3IojdRT1dy0ROpP62IA0syOA9qJATMRZqFiANwPw98UahArW0Q +MpT1s/bUWf2uGzAbTHQw8ta4xYBbbAO3AqIAbr7XhRQS+O275JVU65TqQ2dlKoSp4D0aAJhxSDiE +0qXyfFXek8gumyx6wk+6RPNRBiMJi0BF2bEIC9TsIrBEIUUtLEKY+KMzHq8fxK8OYjvoXj2IiaAL +NJepugtA4yYueOpln1wdaB3ojL/GBdJdPlucKWcgBIpMCZcfq6fa9IySJu0F5JAy1jQ5MzQDCT3C +AHmBI8m9J8m+KRiQgsALPqby4/H6USBWOcPhsOuAVgyRDzYYkGMeRS9KCB95pZmqDs8F/a6CYn5V +Ft0ZXewFtLxG3KFnuUOq5+LnWh6Y1LPQqI+YLIRPX8etyP5lIcNpDcAKmQlhbUb8ZjZbwVbPXGgb +QEYUC4xEzLEJIVcrKYTs2DbzlEA8hY13AmT7o7HPgWL74bAaCNtLa9xGeKbQmarABkPA21UOLMC5 +0OEaOld5m0ytT60D2UasTUNRqvRb1A4gBSz7cSCpHusrSblCUjWYuNcxnUYAWctC+syFLMSmXASz +qHDYA3Xpnpx9xg+oZldoswm/crbjDxH4zB0Ai5xK8eW9lf9XyLyX8OxGMG0KD0t44NxQhNsKeKyl +gsekGoSgHW6t6PPX+wOSSnsJSmheiJ+O7gmph6bBPny2mj6Bm0lIJrqQ7kQtV9R4sDL7t1P2azW3 +PIGAwwpN08TSj2p1MGqS1tqkDP0dcFarPZ39gH1ZfPIW/v17xjnWO47V6wx7o6pJlZAiyMOogqnM +8+sExHKfLPwvHPZZ3xZ4pPSWdZ8LvxUrzrVeFB4TwQB2JKRTRxo6iu5aupC1pvEu8gb3hg5OCFP9 +6OInHojusnqLfV9RkI1nFSi+19/FMa1tZLGmsiPydpEhohRBUmgX9qVlz13W1kMVSDF61EyfUHio +h1txbSqSF4SUkp7qfQpcUNDGMCy6A4mWt8gam8SwY1UiY/BPoXNdsE5je7N9rPfrLcakdU8fRbe+ +FvCPjJsj8eQIbAq7JeMH2YHS2/0rUCU0EXGhQJynzm7Vgau/+9UudwXYt9+Kl/VN0H0G1OJwBp40 +egIFRu0VykxioRIcAAC6OwEaXKFhtRkVhzUxndQ2eMyULWIsUm0kWpwgVakUppjUEs+erVcyP0Fi +TW1qad8pNoJWcS6QGeAyauwgdauBYwbDpo/ahQph78LFtPMZX4Nc9Kg6HIp4L24wZR0n6wcUG9lw +eKt80z7XbE0aYm6CR7LLjIML6jDIFlQ7D70WJTPorSeiX0qmIvp5AhxmmB9hjQK7LaAmq/AJsptc +dlfJe+cpm4TZMRMZyAPnC1UQky+VywtPWMTkO+kyIXjasm4Eic094RPpKOnCzrxcHLeRjssbNtJ6 +15ymdFh1c6WARvwEBqzU+ZN4THkZKjwcRjajKB512ItlIdwf9YdneVqWOeFHlv3LG5H10LZCGnU/ +B3T4fFE8YeUe74uSOWjhpCh7s/KqI+k/sO+obGvhTcwY+1jn8M93zLT1c1CWWOmWpqnx7x3Nj3+S +Ll+xs6M3mbonhjcvq1UqeInDYk/iSexuDH6jgLC5wl7NE1H5Op7gPZ1Xly9+/tGSXZYl3erEfcv7 +SkprAWkLBEb/bIiEjden4JWAeT2l+6rDQHaPxmdeDhDMPa2LJFRIMyyU1lZlQaIoa4j/FPCMakmU +zpOnlGBHrCMsUCGhJ70ykkhYQVSOjnUNplzGiPpNPYfG8ANuD3JC6UtX6vLr2qEtLfmpRaxaE4c8 +ng6B2LEECLrTWyyBBrjspNgwX25NKBiWPLQ7VsLrkwI1ag+qbl2DhAsUOlTqT+UCAWhx3QtKr1av +EYisepUKUeLEiwtBIScS6loISZdTeUR7uVVku2aiMhXdnouui5vqGNkyQZCqOu0ikajgm3xQW1c8 +1NYgIxCtdWK4ZONRReg3sQj8CpEx9cU9Q0iVtOqFrb58sFcb4Uv3EL5cA+G/1T3Y2Dr4y32DL900 +MDsG+yTGw8ZegpkXB1jCqC4RtpqIiA9tKd7a/Jpj3SHnU8OYxJIvx28fgOlsuhSmy/VvJehVKaO5 +Icyie1ROpM+2LrKReTsDvC0YOgOsje4ay+C1oZDRUAudO4UTI60BMoEgE9Ced40V+gFct8fAJQjf +IC/g7txI2kflBo0tJtkzqd3XFF/GYVc3l++f31y/x4NiZQVe9FUQKSfh1elfnr/++XKH7+dQQKAr +n5JK5FGtmj7r12v/TaUhHMUWjV5Xubig0mouqj/qmseZvG74MZ4v51su0gg6G37WL9loK0rASBPF +inivyvDg5RWXpt1SsWDtXfrGTuUujcs+tbtEGr3yblp9oNYTqA+bhXzspWKQLC8dKl9f9Qta2cXY +1nbC2toyDrNybXUnFFMKAUJkVgvIJSm2rS/hCXDiA0Sa+pIiYBvdBlFirNcR5aUpVWZsrkBGvsd6 +VGV07OGmi3fH5OtGtSzjSJE5PmXSGWqO+sg+Pq2evk3JL5c6Y7wiwYb5RqkNR5VimBTl+Y70wxp0 +DeEcmbLSSWl3D4/0i4j6HMGII8WQ0zo0VaQEOKWjSKdQjtX9psnN0zU915evV5TW3jWNoKFgqgoT +5puQOjpVqORZlma3ojx+dKgFj/LXQ9lHOayRwapVlcBS3/2QfVfPS+XLE0iiuYT4rDYFQoyjqh6q +pFMmEBIVolGaYbyiQVBgha207KReATvfSlF8abKcVioue8ac8kL5iovbw+vpzJn61iIiqxVXZFah ++NpkXoRPsDQl8GrbmCxJD/w9Ie9qwWOse8BQOqEapGQYTHlBrlxyS6dxYhiGPG75gsaa3wwqv4tq +gNVwT1K/INtchIfzUb9PdkCr6oksJNSUrlI20Vdkv/2uSU+vd4nXxC43vCUG9eq8yDlVZP38Cj0z +a/R6Z2Knqjxb+2mt0CuBNVfo1eiGIr0SR0shSVG4TKLridQKoUPyj2emfgnWml8Zkas01PqVD9RK +nBWSrwYoxVcDhtp9bo+ghLOlpNo6Xc36vI561ytZxACUXhGNRiCaDF3doVhlxA7PtSlUYT8qJx7r +ZQul4zrDvv22rBxXheM/MwyP5sx6ivNZNfzTitDuVXkt6hkV9XteYCmI6nO1PUtT1Uv2uxTt2W6d +lcbdmDUr3cGUuaW+Q9hVQ2QH7tYF9UPNjvDNg40BVOjGYXkL4RBMgOrGqboGTZxOl0UeR4a+U5Q5 +PKXKVHnKTya4ADXaR2kOpJk1zqiW+MvilXak2hJk5FFAV6shHYb8todfhHENy9/WsSAFBvaQYsio +LaM43aHUPbNe+l+zb7OCXn7BUJ72yzQFvkBbgKnOwE4uHVsDu3UDav2Ayj9/Ul7aKOPqseFMxxqS +caW3JMAlkACFrVp0hjOYzpJmIos6nY7ymMIgFY3vGgxMnOCkWsZW6vrsmXyon2ZtVfKLBEzpOdjQ +rMm7b+hUrEWrZZJr+QOW16r/r4rWrLdUVQ0tratrU9TZGE9EsCEhLLNLURs9L5XjL/SNmEbI9KPx +74rrUmLlPPIuMuZKiCKcjDbl3DowatjaF7+MEvZM/GObVeoDY1O6LzKW0H3Yp43odsNXqJodx5oj +bMAvu9XrmAkjt9XlGvbSCFKkhoTRY5iMed2UaViOqWclREfFCmfj5UzdBhbQisZ2KPtVbqqqszZg +hdyMHPruTmtxukp2tIf/ae/aeuO4rfCz9CtGQBCsJdXeIecaV2mbNkXblz60b0FRTD1yu4BiGVkp +bZD0v4fnfLwccjizs5Lc2oAMJGtzeL+cOz+iH7JY7vAmXqLi8MHJyaB7p9452cd6Ys3I3t+7FYb8 +ScNNBM7EGj23iDEXjgjvhSS2L+YVNDC8MLZbQkMevv28uN3PNEsUgBofbiIa9/HQDwjF0Wx8eZWT +thYMFslGD4KXEb0IKvrtze2/EQdIPIjibX4wIrF3Kl2PQeI6+e/pycWFmK8HEqHJRnVCpV2Fsyu5 +KG4Wb/e2GmJfwQrsruUFdKUvvMHFVSi5XLaS6/+Yk0njTyuRmyPmlXYoycnhAxLuObItyHnjLr3d +hDKRpkzL9Ge6R/Anvo1AfjF0z5wto8mN7Na6f/ftcGf29Vjc3b+/cdcejYQk5CVERXy3M72xXr4I +cylO4vk8iLMzRTnwm+rckyP+5+tcHdYLRFc83xF8B2mluNeZvTQaNSTss4LXfMXFlxo7cDE1agMH +PG3DRRM5YKukLbNrh/ubuwhXQ1bqZtjQuS+iKSIr6GQoSSKfmi0MzD86k19o+2CbYnkG//dLN5kD +2ry0Ax9YS7FnIelrKJ3rtK1o2nVR5Y90Ev51+/767f0NBS8z5doxgos9YFPP+NnZmRlSMR34P28l +pFkBVCKJaibOQXZmPveBzxcXm0j6P1Kd80FwZ1NTxSadqMASLH5OzCBeFBzydiJj2ewOPzk9mdPd +J1V9k5b+W0xsC2d4C1F1u31kVQabdjN0vpHhFo42p3O1XnV29o15e4BbJcOwXR+EccDTrABu54Cp +eAv8ooiCqK/HX00NBNEEbKPBs2vYtXt1tcHQw8bZpbPhAkMy6311VexepqkcY+r4bWo4SUrA6vJi +voNnj+vgWb6DP/1UzPbwbLGH5r8YJMABfxl6vDdrZoMsoPYvnVsvw/nldhG6cnCWkt38nupzkx4L +bPbj1OAlCznvhzvMogwd5Kj+VK6zxxazdXEh85pzi+SVfRCrbBfNk3Ie9d/fDPu7Xwaq/uWGzq6h +u7KeS9FakI39NCIYV05i2lSx3FbWaxVpI4lnqbC9GJquqLZyc/hFJjzX3Ru7YpHIyCk7a3ykdvJ6 +wvkGWc9fIPO8TmCbYtVgn23JMcR39tNMy2mTNs4mRB/PaiQTRXNWp461nsifZfWVleoAtuGxGsGx +2oCnAREJMNvpew4RHXJApf8YKMie4aGY8aQLZVV+GEpW7oaNDQfd7KAtSkfhdGusDYUsjg6G5JGM +Ld8YMv/vVl2zyw5MGoViIKHEjSaNRPGXScBj9HUh8nEu9tFHHrjwRz7krSr6CUzMgbgZWm4p4ad+ +79dpfTN14DxO63htutUWZRMqCHpeuKrhYnPE/dWDdspI9Q8ucdlhnzd2boa5zGae4Pz42Y4mQyAB +hzMVz4dsMVidGXuuK4uytXxaRidNj+kl9MvdPiznW2bn1xSJQ0z+AvUMaZeCpyxCHJ4fqCRw0aL/ +RWyir6a9mnH0zzcUe3LnppT0Z48TvTy7guYu1cgzAgNaTApZkrU2Uh+mPt9cbOtDe2NP0cdDrwAH +ep6LsEpDqMa+4mu0FZeZuQpuyc1rk7uxl25tCxblYU+2YkbG2hOEwOhi+20r80dp7BlRqO/yzQsT +uL0bzvcgtrZ5SlJF21A8Y8tpIkKrENFJVLjtDQ0ey840pSnEcWtIFds/3/INWELHXl41QRrIWxIM +oERoir96hTO/YHMwU/trAiMPV3cZP2N494N1hIVLn7BOTmvkoAEKMN1yiCX9yGv6C+Wd0c6U0cUE +7iyJ9Xss9tWHBg5Q25ruhqutXV8KfiVgYw68dTH5FiM1xlg5Jri2zaKvJAC/vdlp9elYV+FGt8X2 +/GSxWY6ZoyaL2hIHII+qrYG3i4hqYaxP7PRjVYf1a/z6CdSXY/pWZ/FgHHqI71xTNIAUtbe9LbWp +e/bUE7EylEfTfis100/8WJqkeype1jX/YKClHeiB+H4mVKi/41rEqUbxV69mPcUmM0CMt+00c9bB +O6rSdKs3vxWaqZQfhqoRC97Y8SfeIzNJWMGmDkU6oj3mAGy5JDOiyLhvPlX4ZDlI8QSW91Fv+UIB +ftATbZGxHTQ2J/F4dBXWU1fAW+EfrM0BWXe/q8hMQxiZowYCBX5shTUqrPuQhNsOuhGda1oktSGp +RcFWFATqCn5cEgMf6K4LST0C63slkhBN77k0bWXmnJXgnNW2Q1Koqyq5Lvy4pIZWtAI6Nn7sF8xw +JWa4qpBUyaQaSWGOovPMr77wmT79LWO87AVb/fo3vyvwwsvLp78Boeh0Fs+Phjzi0RA6QDg/wMN4 +vrHxfGMj/bPqxsbAbGcZ+djz4eLQzYShqxgYJo24NqQDvLp0vPrpompNpZ2hJx8kHHYoFdX9KQVf +jmXFzAs/9GnFrUaTu/ZL/PDLhwMEL0ztxxq9OJYQC0onFhyOAzRFOhTp5opkZTyInr3d8M+BeZ9c +YJ5RBUC3Ok+3Vt5+VQCOoB8QxNURYKZog6JNTCuPjf4yGgYqKptU0ctFZRm9nVSIjzDSaVT2hRjV +2clcG6U0Ks3St9JuGQKdVLrDJyeFF6RYYcYaP/VHOlGMcl1BubaM8MN5OYzKx3RMdYHQr3IXmII9 +CjqN55DEZnRHNNVrWWKaC8vUtzLXAex+o0JCX9yWstRjHQWjLqHDlb7LeZu9yQiVsPS9PuqBgFEr +9F+VbsX/5zZ90wfow6qWc/hAw72pDRqx6membmqbNyo+plvPTfeR1nej32BavUa7Hl3VlMV0eNV3 +jTneZO/YfPsEtnXHtZet6pbH6BpGg7pZmrpVJvBRs8lo0M5ytMLIPWo4SvETH+5DNmhTFmpoW60t +GyzMgzZctX+G6V5vCn4SmG6Yf+zbF49H4J7Cbz8ce/sYS1OVReV+88YZkjMie0ZYd7ZYUDzlKF7x +wNBmjmoeFexzyj8O+FBLqzOydvSgB9bNAmXHsOPHzJvOApInZnjDjcmP4iOTTzNOrbWBA77AfJRA +JvOqp3x87v9zOEA8RFn31Cs9X/Xyi0Kr/PXzufNO9/mOz/jU5wvkvOJRiQkvdKa2dbm9IzyTedb1 +zBs362aeH8iMt9gXOOAMTtTwI3zBXjWflJn4YIX39ZS9ZZoNeWpqyHOTnHvdzD2JJrCVT0O3HEJJ +wCYh3G96c7OR+cLdq5gEXIa2geMEEbVUwdDkLnFlr2+NJcIjShsfcSi7ansjvQ3kB0P2LCadNBmk +gVmzoVhGYWqKXoMQO/+J9gyUJZ5Vjzc84csNc882eFZQ02xAoF376j2FUGSfvacP9t1789fTNWxG +ZR+LmHh74fqEs9IhW1FdAcVqhAavsTkjNKuCu9KiL61LgN5QOr2BkyAKVF1IqpGrFrlq8iqbJGfC +tlJDYCcPA1zhqtGBWnSgQQea0vY7MdZQwD4lwhGsttwnZMQMKD8FqoLJoap87apGnlqJJCjntZuo +xIlMJwiFWlEoDhVAEswmbRgLzpw4epSE1jrfGmDcVO9a0yXWtXRU53bPqUCqL9swYF1CHS17vwWg +sStXudbQ97SvHDZw7W3gx9iquDxaqHwLscN54m4+/ukHVtZQqV8BbabeCXrKQViuflFlVgr8jIEO +ak+5JxLQHwz1ggg0NryXGmyljFjlRRTEYgxWvJ7kDNJJeCslm1EKJoZJlEVLTKLloKhwESoulkMS +S3IkzxksQNRnCosHD/jzFB7HzdiUrZo/C0yXvsZPkcayi8c2M1PRg18GlURIwRs/BOLLJR7DLrWS +eV0fN7LD5KQr656nN5C4Twidx1BOCBL21Hy/++6OTKMJKNRIYYlqS2IE5rHvo+wHMHgMZwJRVVVU +LH7+wdBiEG3dTHMFwA9DaqFeNv002woITN0oJoqNtpxpTrTxu3K9bEPVCbuxq+GbbRJw05YkT1g7 +D56T/Myh7drIMOwhUxvME4IeFWXFuJf61OyClQ/LezIXPSoPh637s/CoPDE8Cp/RuqgbIwh11IdE +aZ3qrJGKGmuorj9OH/mjdeNEpCPSPCOqEVHZROuI9MRpfUIrTD9KHTD9Fh/JtMFEv0s/p9pcRMIS +3S39JjS1iLgJvWzslaFAQ9/zhk4bTzSwSGOa6FsM0U7ba1tZTpzk9lFz9GoSZ8QpjJSqWKdCuAJT +32qJER3kQykbijbRMhdaZkKHeNAiC1riQJIBNWBAkbpHI0iYT0NBZWPZkRbKscA6xEG+Iu07fqLH +CLUwj5VO9vaYV1T5MVjKpiqGJlZWNHwVmMxDMZs4HJPGUWM4Lf6FwWmzx+in5EStkKjxrwr/qump +NksYX3riaBmsp4m/Pv0ZR559DrmcAAA= +]) + +AT_CHECK(mkdir tmp, [], stdout, ignore) +UNGZB64(rcsfile.gz.b64, tmp/rcsfile,v) + +AT_CHECK(MONOTONE --branch=test cvs_import tmp, [], ignore, ignore) + +AT_CLEANUP +(END) --- tests/t_rename_dir_add_dir_with_old_name.at +++ tests/t_rename_dir_add_dir_with_old_name.at @@ -0,0 +1,28 @@ +# -*- Autoconf -*- + +AT_SETUP([renaming a directory and then adding a new with the old name]) + +MONOTONE_SETUP + +# This test is a bug report. +AT_XFAIL_IF(true) + +# add 'foo/test' file +AT_CHECK(mkdir foo) +AT_DATA(foo/test, [test file in foo dir +]) +AT_CHECK(MONOTONE add foo, [], [ignore], [ignore]) +COMMIT(testbranch) + +# rename 'foo' dir to 'bar' +AT_CHECK(MONOTONE rename foo bar, [], [ignore], [ignore]) +AT_CHECK(mv foo bar) + +# add new 'foo' dir +AT_CHECK(mkdir foo) +AT_DATA(foo/test, [test file in new foo dir +]) +AT_CHECK(MONOTONE add foo, [], [ignore], [ignore]) +COMMIT(testbranch) + +AT_CLEANUP --- tests/t_update_nonexistent.at +++ tests/t_update_nonexistent.at @@ -0,0 +1,10 @@ +AT_SETUP([update to non-existent rev]) +MONOTONE_SETUP + +ADD_FILE(testfile, [blah blah +]) +COMMIT(testbranch) + +AT_CHECK(MONOTONE update 73070030f7b0d0f3d4ee02545d45ca4bbe5e189f, [1], [ignore], [ignore]) + +AT_CLEANUP --- testsuite.at +++ testsuite.at @@ -37,6 +37,10 @@ # Save the PWD so MONOTONE macro can refer back to it _ROOT_DIR=`pwd -P` +# Pick a random port, so running multiple testsuites concurrently on +# the same machine has a hope of working. +_PORT=`awk 'BEGIN {srand()} END {printf "%.0f\n", (rand() * 450 + 20050)}'< /dev/null` + AT_DATA(test_keys, [@<:@pubkey address@hidden@:>@ MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCfN/cAMabgb6T7m8ksGnpQ7LO6hOdnc/7V yivrRGtmpwSItljht1bmgLQF37KiSPoMEDUb1stfKxaMsYiy8iTyoQ+M2EVFP37n2rtnNZ0H @@ -336,13 +340,13 @@ # note that NETSYNC_SERVE_START is _not_ a special case of this macro. m4_define([NETSYNC_SERVE_N_START], [ NETSYNC_KILLHARD -MONOTONE --db=test$1.db --rcfile=netsync.lua serve localhost:5555 $2 & +MONOTONE --db=test$1.db --rcfile=netsync.lua serve localhost:$_PORT $2 & sleep 4 ]) # run as NETSYNC_SERVE_START(collection name) m4_define([NETSYNC_SERVE_START], [ NETSYNC_KILLHARD -MONOTONE --rcfile=netsync.lua serve localhost:5555 $1 & +MONOTONE --rcfile=netsync.lua serve localhost:$_PORT $1 & sleep 4 ]) # run as NETSYNC_SERVE_STOP @@ -354,7 +358,7 @@ # run as NETSYNC_CLIENT_N_RUN(2|3, push|pull|sync, collection name[, expected result]) # first argument chooses whether to use the 2nd or 3rd database m4_define([NETSYNC_CLIENT_N_RUN], [ -AT_CHECK(MONOTONE --db=test$1.db --rcfile=netsync.lua $2 localhost:5555 $3, [$4], [ignore], [ignore]) +AT_CHECK(MONOTONE --db=test$1.db --rcfile=netsync.lua $2 localhost:$_PORT $3, [$4], [ignore], [ignore]) ]) # run as NETSYNC_CLIENT_RUN(push|pull|sync, collection name[, expected result]) m4_define([NETSYNC_CLIENT_RUN], [ @@ -551,3 +555,10 @@ m4_include(tests/t_netsync_largish_file.at) m4_include(tests/t_update_off_branch.at) m4_include(tests/t_setup_checkout_modify_new_dir.at) +m4_include(tests/t_rename_dir_add_dir_with_old_name.at) +m4_include(tests/t_rcs_import.at) +m4_include(tests/t_cvsimport2.at) +m4_include(tests/t_lf_crlf.at) +m4_include(tests/t_add_vs_commit.at) +m4_include(tests/t_update_nonexistent.at) +m4_include(tests/t_override_author_date.at) --- work.cc +++ work.cc @@ -88,9 +88,9 @@ } static bool -known_preimage_path(file_path const & p, - path_set const & ps, - bool & path_is_directory) +known_path(file_path const & p, + path_set const & ps, + bool & path_is_directory) { std::string path_as_dir = p() + "/"; for (path_set::const_iterator i = ps.begin(); i != ps.end(); ++i) @@ -126,7 +126,7 @@ N((*i)() != "", F("invalid path ''")); - if (! known_preimage_path(*i, ps, dir_p)) + if (! known_path(*i, ps, dir_p)) { P(F("skipping %s, not currently tracked\n") % *i); continue; @@ -163,16 +163,17 @@ extract_path_set(man, ps); apply_path_rearrangement(pr, ps); - bool dir_p = false; + bool src_dir_p = false; + bool dst_dir_p = false; - if (! known_preimage_path(src, ps, dir_p)) - { - P(F("skipping %s, not currently tracked\n") % src); - return; - } + N(known_path(src, ps, src_dir_p), + F("%s does not exist in current revision\n") % src); + N(!known_path(dst, ps, dst_dir_p), + F("%s already exists in current revision\n") % dst); + P(F("adding %s -> %s to working copy rename set\n") % src % dst); - if (dir_p) + if (src_dir_p) pr_new.renamed_dirs.insert(std::make_pair(src, dst)); else pr_new.renamed_files.insert(std::make_pair(src, dst));