The unified diff between revisions [dd2f27b8..] and [016b3b68..] is displayed below. It can also be downloaded as a raw diff.
#
#
# rename "tests/t_log_nofiles_merges.at"
# to "tests/t_log_nofiles_nomerges.at"
#
# rename "tests/t_sql_unpack.at"
# to "tests/t_sql_gunzip.at"
#
# add_file "tests/t_log_selectors.at"
# content [3d000a79a2acdff3df5c7a8a804d2e38aa035dc5]
#
# add_file "tests/t_pivot_root.at"
# content [2bf3634c3c1a16c375a85bc5f403992422cdfc8b]
#
# add_file "tests/t_pivot_root_revert.at"
# content [bf2c402b7cb49ebdd178928ea01372deb68858a5]
#
# add_file "tests/t_pivot_root_update.at"
# content [e4f51059ec68ec4f187cd3593eeb49459aea3b5a]
#
# add_file "tests/t_rosterify_root_suture.at"
# content [ff625956c64676b2b33f9ccc9f9a45b7b7587318]
#
# patch "ChangeLog"
# from [e130fcd32c009c5f7ad8b31d5736aed3e9f67c09]
# to [cef9fe8e359d630eb8f61133684772293748eade]
#
# patch "app_state.cc"
# from [d6bd147ff69418001cff7cfd08e7ec18deca23ab]
# to [4990c26751504dded9cef9b1c6ffa66bef0d2b32]
#
# patch "app_state.hh"
# from [7fb16348486ca507f22a99d6aca9ba2dc4a658c0]
# to [03afbc7ba543f0b26f8ddf70d97c05e872cdb36b]
#
# patch "commands.cc"
# from [8d15447176db8827209c2feeaaf0b0eaa7e2e1fd]
# to [0fc12a37debd7db7812e2670afcb99d787f869e0]
#
# patch "contrib/color-logs.conf"
# from [ffe3e7270a2952c508db2f2d9c3df82e05c859f4]
# to [87e8ceac1e0a8d173e2a0da01e659d048824e9ed]
#
# patch "contrib/color-logs.sh"
# from [90a0de6aa87b7f4b39f7947fd1d359a3cc936385]
# to [4e04daeee4ee8ce8bf6ce45f074ba16faf50ccf9]
#
# patch "contrib/monotone-notify.pl"
# from [aa93d7f9f601b51d607bd4d779e472067c41d5a2]
# to [d7f551f0f332f56785aaa59e99ade7400c8da84a]
#
# patch "contrib/monotone.el"
# from [3dc1c23d499d1aa015ed7f145416a241a55f054f]
# to [9e1a1ec218b98cd38c6126c48f00a1d585e65a13]
#
# patch "cset.cc"
# from [a8497f9a82330f842cda2f242e97ef48e3a6b9fb]
# to [5fdac8f01ad19e4a427e40aa4245026b534422f7]
#
# patch "database.cc"
# from [70d4d8f0c43de5e18bb023fc2c87805c0cdfa659]
# to [61bac503d11d0d68da007b53ec4a7f31e0453cdc]
#
# patch "file_io.cc"
# from [3214c2cad3ec630d8466926bd4bae693de9184a0]
# to [3ca8050b61b62ef9010b0ebfda755a0af9269104]
#
# patch "file_io.hh"
# from [2082dc3c8480400f32fcbe1c4d881d7512de2204]
# to [362691f10f63d93e7cf83f299fe5aa0b4dcbee17]
#
# patch "monotone.cc"
# from [6626e22d6ef4d9c8d3380a2f498599dd57bc6d3d]
# to [29890d9e90e828fa96d845cb881bb024a8267d99]
#
# patch "monotone.texi"
# from [1fcc35f2ac3ca9ba692509cd29f6f5ff01b6616a]
# to [d62e740d5bf36c317e4ec3fea155132bd7ba702d]
#
# patch "netcmd.cc"
# from [5a63ccd88ddb02cf5853e13ce3fff6ea20851a53]
# to [da3773c93069c0834ce0b3caf34020305dd7d8b2]
#
# patch "netcmd.hh"
# from [22664387cea0916b87288113ec5b559c2c49eda5]
# to [e290b45f5acb01bfe181832d4750275e05b2f98f]
#
# patch "options.hh"
# from [16194449c59ae0307ab9bbf15ae879f0f8063fdd]
# to [216cb82f6f82b63b0f1535b39bb985a237b43359]
#
# patch "paths.cc"
# from [c13e9b0c44a37a70e6c7e6d5c8b8869e363ccab9]
# to [05c27908836d28a468070bb8e7a808417b8401f1]
#
# patch "paths.hh"
# from [054a74b153b42a34140f2776f468bf79c844fa64]
# to [e81d1f0e7efdbff539b8b92f04ad357770130fd4]
#
# patch "roster.cc"
# from [5313de9037e0af779b593f9f432155891a70374a]
# to [ccbdfd50a2a99c49598ae638a013a095f232c876]
#
# patch "roster.hh"
# from [0647777b7cab5a2c17419998351f049eadc706d5]
# to [9ec5d3bbd5751f987a7591a3d577002a627a36e3]
#
# patch "roster_merge.cc"
# from [aa38469bceafec9e94d2ba9c291cf08d6fc90e06]
# to [d1d307d2cc0fac8f4c50963b1563edcc3df26d86]
#
# patch "roster_merge.hh"
# from [9227745f9aeb67c68ca363dc1df62537c8bcb873]
# to [3a86138ac40adb1f2736fc9f348988b91aea2ff4]
#
# patch "schema.sql"
# from [5e315b54e2c1df1f315c3aff2ad9a551332debb7]
# to [c68ba3a5f158efdf6cae10d6b307a9cf0d35be44]
#
# patch "schema_migration.cc"
# from [9f3a9b8a4a509edf8af01c796cbc6588e902e888]
# to [7d215b15eb77f65457092c0cc1553f4ab2689a4e]
#
# patch "std_hooks.lua"
# from [87a925a89f17ae312390049e28296bbb9f7ee170]
# to [4ca1188ac09063710baa429986649f2c3ad13083]
#
# patch "tests/t_log_nofiles_nomerges.at"
# from [958b5e4229b1afd2c7ec131d0a239b28d792815f]
# to [dedc7b333ac5e779f29464a1f62285ec787b6dd4]
#
# patch "tests/t_migrate_schema.at"
# from [9d9a73cc20f8e367f4c828484e78c19224614b93]
# to [e5b24dd9ccc44e36b20d1b1dc89509f0e99896fd]
#
# patch "tests/t_sql_gunzip.at"
# from [1bb994c7c10fcfafc2a0fc9b5dd7c45b5b315174]
# to [1e43988cec90fe9e16a51379b7b832cfc609d122]
#
# patch "testsuite.at"
# from [c8be08d87b48f90c833c326e708aaa06423b1b75]
# to [d67ef3223629641b02551a0a31cbf4644cd60d82]
#
# patch "work.cc"
# from [39e5c9ecd7f5209dbcbb7e631d6fc044296a4a67]
# to [be9eb83e519a1395626b2b29868af63e46a958c2]
#
# patch "work.hh"
# from [2e87d93b08c16ef877483f69594636c480d0f97f]
# to [dc6f1035c0b3a27f9b94bff02d5f650b9da8f26b]
#
============================================================
--- tests/t_log_selectors.at 3d000a79a2acdff3df5c7a8a804d2e38aa035dc5
+++ tests/t_log_selectors.at 3d000a79a2acdff3df5c7a8a804d2e38aa035dc5
@@ -0,0 +1,26 @@
+AT_SETUP([log and selectors returning multiple rids])
+MONOTONE_SETUP
+
+# testcase for bug #15877
+
+ADD_FILE(testfile, [blah blah
+])
+AT_CHECK(MONOTONE commit -b testbranch --date "2005-08-16T03:16:00" -m foo, [], [ignore], [ignore])
+R0=`BASE_REVISION`
+
+SET_FILE(testfile, [stuff stuff
+])
+AT_CHECK(MONOTONE commit -b testbranch --date "2005-08-16T03:16:00" -m foo, [], [ignore], [ignore])
+R1=`BASE_REVISION`
+
+SET_FILE(testfile, [other other
+])
+AT_CHECK(MONOTONE commit -b otherbranch --date "2005-08-16T03:16:05" -m foo, [], [ignore], [ignore])
+R2=`BASE_REVISION`
+
+AT_CHECK(RAW_MONOTONE --db=$_ROOT_DIR/test.db --root=$_ROOT_DIR log --brief --revision d:2005-08-16, [], [stdout], [ignore])
+AT_CHECK(grep $R0 stdout, [0], [ignore])
+AT_CHECK(grep $R1 stdout, [0], [ignore])
+AT_CHECK(grep $R2 stdout, [0], [ignore])
+
+AT_CLEANUP
============================================================
--- tests/t_pivot_root.at 2bf3634c3c1a16c375a85bc5f403992422cdfc8b
+++ tests/t_pivot_root.at 2bf3634c3c1a16c375a85bc5f403992422cdfc8b
@@ -0,0 +1,52 @@
+AT_SETUP([pivot_root])
+MONOTONE_SETUP
+
+# possible problems:
+# -- the new root doesn't exist
+# -- the new root is not a dir
+# -- the new root has an MT in it
+# -- the directory the old root is supposed to end up in doesn't exist
+# -- the directory the old root is supposed to end up in is not a directory
+# -- the directory the old root is supposed to end up in already
+# contains something with the given name
+# then make sure --execute puts things in the right place...
+
+AT_CHECK(mkdir workspace)
+AT_CHECK(cd workspace/ && MONOTONE setup . -b testbranch, [], [ignore], [ignore])
+
+AT_CHECK(mkdir workspace/dir1)
+AT_CHECK(mkdir workspace/dir1/dir2)
+AT_DATA(workspace/dir1/file1, [blah blah
+])
+AT_CHECK(mkdir workspace/dir3)
+AT_CHECK(mkdir workspace/dir3/MT)
+AT_CHECK(cd workspace/ && MONOTONE add ., [], [ignore], [ignore])
+
+AT_CHECK(cd workspace/ && MONOTONE commit -m foo, [], [ignore], [ignore])
+
+AT_CHECK(cd workspace/ && MONOTONE pivot_root nosuchdir foo, [1], [ignore], [ignore])
+AT_CHECK(cd workspace/ && MONOTONE pivot_root dir1/file1 foo, [1], [ignore], [ignore])
+AT_CHECK(cd workspace/ && MONOTONE pivot_root dir3 old_root, [1], [ignore], [ignore])
+AT_CHECK(cd workspace/ && MONOTONE pivot_root dir1 nosuchdir/old_root, [1], [ignore], [ignore])
+AT_CHECK(cd workspace/ && MONOTONE pivot_root dir1 file1/old_root, [1], [ignore], [ignore])
+AT_CHECK(cd workspace/ && MONOTONE pivot_root dir1 dir2, [1], [ignore], [ignore])
+
+AT_CHECK(cd workspace/ && MONOTONE ls changed, [], [], [])
+AT_CHECK(cd workspace/ && MONOTONE ls missing, [], [], [])
+AT_CHECK(cd workspace/ && MONOTONE ls unknown, [], [], [])
+
+AT_CHECK(cd workspace/ && MONOTONE pivot_root --execute dir1 old_root, [], [ignore], [ignore])
+
+AT_CHECK(test -d workspace/MT)
+AT_CHECK(test -d workspace/dir2)
+AT_CHECK(test -f workspace/file1)
+AT_CHECK(test -d workspace/old_root)
+AT_CHECK(test -d workspace/old_root/dir3)
+AT_CHECK(test -d workspace/old_root/dir3/MT)
+
+AT_CHECK(cd workspace/ && MONOTONE ls missing, [], [], [])
+AT_CHECK(cd workspace/ && MONOTONE ls unknown, [], [], [])
+
+AT_CHECK(cd workspace/ && MONOTONE commit -m foo, [], [ignore], [ignore])
+
+AT_CLEANUP
============================================================
--- tests/t_pivot_root_revert.at bf2c402b7cb49ebdd178928ea01372deb68858a5
+++ tests/t_pivot_root_revert.at bf2c402b7cb49ebdd178928ea01372deb68858a5
@@ -0,0 +1,47 @@
+AT_SETUP([reverting a pivot_root])
+MONOTONE_SETUP
+
+# This test is a bug report
+# I think the problem is just generally that revert does not do a good
+# job cleaning up after renames?
+AT_XFAIL_IF(true)
+
+AT_CHECK(mkdir workspace)
+AT_CHECK(cd workspace/ && MONOTONE setup . -b testbranch, [], [ignore], [ignore])
+
+AT_CHECK(mkdir workspace/dir1)
+AT_CHECK(mkdir workspace/dir1/dir2)
+AT_DATA(workspace/dir1/file1, [blah blah
+])
+AT_CHECK(mkdir workspace/dir3)
+AT_CHECK(mkdir workspace/dir3/MT)
+AT_CHECK(cd workspace/ && MONOTONE add ., [], [ignore], [ignore])
+
+AT_CHECK(cd workspace/ && MONOTONE commit -m foo, [], [ignore], [ignore])
+
+AT_CHECK(cd workspace/ && MONOTONE pivot_root --execute dir1 old_root, [], [ignore], [ignore])
+
+AT_CHECK(test -d workspace/MT)
+AT_CHECK(test -d workspace/dir2)
+AT_CHECK(test -f workspace/file1)
+AT_CHECK(test -d workspace/old_root)
+AT_CHECK(test -d workspace/old_root/dir3)
+AT_CHECK(test -d workspace/old_root/dir3/MT)
+
+AT_CHECK(cd workspace/ && MONOTONE ls missing, [], [], [])
+AT_CHECK(cd workspace/ && MONOTONE ls unknown, [], [], [])
+
+AT_CHECK(cd workspace/ && MONOTONE revert ., [], [ignore], [ignore])
+
+AT_CHECK(test -d workspace/MT)
+AT_CHECK(test -d workspace/dir1)
+AT_CHECK(test -d workspace/dir1/dir2)
+AT_CHECK(test -f workspace/dir1/file1)
+AT_CHECK(test -d workspace/dir3)
+AT_CHECK(test -d workspace/dir3/MT)
+
+AT_CHECK(cd workspace/ && MONOTONE ls changed, [], [], [])
+AT_CHECK(cd workspace/ && MONOTONE ls missing, [], [], [])
+AT_CHECK(cd workspace/ && MONOTONE ls unknown, [], [], [])
+
+AT_CLEANUP
============================================================
--- tests/t_pivot_root_update.at e4f51059ec68ec4f187cd3593eeb49459aea3b5a
+++ tests/t_pivot_root_update.at e4f51059ec68ec4f187cd3593eeb49459aea3b5a
@@ -0,0 +1,49 @@
+AT_SETUP([updating through a pivot_root])
+MONOTONE_SETUP
+
+AT_CHECK(mkdir workspace)
+AT_CHECK(cd workspace/ && MONOTONE setup -b testbranch, [], [ignore], [ignore])
+
+AT_CHECK(mkdir workspace/dir1)
+AT_DATA(workspace/old_root_file, [I'm in the root to start off with!
+])
+AT_DATA(workspace/dir1/new_root_file, [I'm in the subdir to start off with.
+])
+AT_CHECK(cd workspace/ && MONOTONE add ., [], [ignore], [ignore])
+AT_CHECK(cd workspace/ && MONOTONE commit -m foo, [], [ignore], [ignore])
+BASE_REV=`cat workspace/MT/revision`
+
+AT_CHECK(cd workspace/ && MONOTONE pivot_root --execute dir1 old_root, [], [ignore], [ignore])
+AT_CHECK(cd workspace/ && MONOTONE commit -m foo, [], [ignore], [ignore])
+
+AT_CHECK(MONOTONE co -r $BASE_REV testspace, [], [ignore], [ignore])
+AT_DATA(new_old_root_file, [old root file modified
+])
+AT_DATA(new_new_root_file, [new root file modified
+])
+AT_DATA(new_unversioned_root_file, [newly placed in root dir, unversioned
+])
+AT_DATA(new_unversioned_subdir_file, [newly placed in sub dir, unversioned
+])
+AT_DATA(new_versioned_root_file, [newly placed in root dir, versioned
+])
+AT_DATA(new_versioned_subdir_file, [newly placed in sub dir, versioned
+])
+AT_CHECK(cp new_old_root_file testspace/old_root_file)
+AT_CHECK(cp new_new_root_file testspace/dir1/new_root_file)
+AT_CHECK(cp new_unversioned_root_file testspace)
+AT_CHECK(cp new_unversioned_subdir_file testspace/dir1)
+AT_CHECK(cp new_versioned_root_file testspace)
+AT_CHECK(cp new_versioned_subdir_file testspace/dir1)
+
+AT_CHECK(cd testspace/ && MONOTONE add new_versioned_root_file dir1/new_versioned_subdir_file, [], [ignore], [ignore])
+AT_CHECK(cd testspace/ && MONOTONE update, [], [ignore], [ignore])
+
+AT_CHECK(cmp new_old_root_file testspace/old_root/old_root_file)
+AT_CHECK(cmp new_new_root_file testspace/new_root_file)
+AT_CHECK(cmp new_unversioned_root_file testspace/old_root/new_unversioned_root_file)
+AT_CHECK(cmp new_unversioned_subdir_file testspace/new_unversioned_subdir_file)
+AT_CHECK(cmp new_versioned_root_file testspace/old_root/new_versioned_root_file)
+AT_CHECK(cmp new_versioned_subdir_file testspace/new_versioned_subdir_file)
+
+AT_CLEANUP
============================================================
--- tests/t_rosterify_root_suture.at ff625956c64676b2b33f9ccc9f9a45b7b7587318
+++ tests/t_rosterify_root_suture.at ff625956c64676b2b33f9ccc9f9a45b7b7587318
@@ -0,0 +1,124 @@
+AT_SETUP([db rosterify on a db with a root suture])
+MONOTONE_SETUP
+NEED_UNGZB64
+
+AT_DATA([test.db.dump.gz.b64], [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
+])
+
+AT_CHECK(rm -f test.db)
+
+UNGZB64(test.db.dump.gz.b64, test.db.dump)
+AT_CHECK(MONOTONE db load < test.db.dump, [], [ignore], [ignore])
+AT_CHECK(MONOTONE db migrate, [], [ignore], [ignore])
+AT_CHECK(MONOTONE db rosterify, [], [ignore], [ignore])
+
+AT_CHECK(for REV in `MONOTONE automate select i:`; do MONOTONE automate get_revision $REV; done, [], [stdout], [ignore])
+AT_CHECK(QGREP('delete ""' stdout))
+AT_CHECK(QGREP('add_dir ""' stdout))
+
+AT_CLEANUP
============================================================
--- ChangeLog e130fcd32c009c5f7ad8b31d5736aed3e9f67c09
+++ ChangeLog cef9fe8e359d630eb8f61133684772293748eade
@@ -1,3 +1,79 @@
+2006-02-27 Matt Johnston <matt@ucc.asn.au>
+
+ * std_hooks.lua (ignore_file, dir_matches): add dir_matches helper
+ to avoid including ignored dirs such as '.svn', since dirs now
+ actually exist.
+
+2006-02-26 Nathaniel Smith <njs@pobox.com>
+
+ * roster_merge.cc: Update notes on tests.
+
+2006-02-25 Nathaniel Smith <njs@pobox.com>
+
+ * work.cc (attach_node): Apparently the tests depend on update
+ clobbering existing non-versioned files... and we don't have a
+ good solution _anyway_, so just go back to clobbering them.
+
+2006-02-25 Nathaniel Smith <njs@pobox.com>
+
+ * cset.cc (root_dir_test, invalid_csets_test): Don't test that
+ root dir stuff fails. Test that it works.
+
+2006-02-25 Nathaniel Smith <njs@pobox.com>
+
+ * roster.cc (detach_node): Add missing invariant.
+
+2006-02-25 Nathaniel Smith <njs@pobox.com>
+
+ * roster_merge.cc (roster_merge): Fix strange merge-created
+ problem...
+
+2006-02-25 Nathaniel Smith <njs@pobox.com>
+
+ * work.cc (attach_node): This code should use path_exists, not
+ file_exists.
+
+2006-02-24 Timothy Brownawell <tbrownaw@gmail.com>
+
+ * netcmd.cc: Ignore protocol version field on usher_cmd packets. It
+ should now be possible to use an usher to redirect connections based
+ on netsync version.
+ * netcmd.hh: Remove unused netcmd::get_version() and
+ unused/unimplemented netcmd::netcmd(u8 version).
+
+2006-02-24 Richard Levitte <richard@levitte.org>
+
+ * commands.cc (ls_changed): I was a bit overly paranoid about the
+ possibilities with C++ and defined an explicit functor for the set
+ instead of relying on the automatic generation of less<file_path>.
+ Derek Scherger made me realise I was a bit overzealous, and this
+ change removes the explicit functor.
+
+2006-02-23 Matthew Gregan <kinetik@orcon.net.nz>
+
+ * enumerator.hh: Another GCC 4.1 compile fix.
+
+ * tests/t_log_selectors.at: UnXFAIL.
+
+ * commands.cc (complete): Refactor selector completion to enable
+ return of single or sets of completed revisions.
+ (CMD(log)): Do something sensible with selectors that return
+ multiple revisions.
+
+ * tests/t_log_selectors.at: XFAILed test for bug #15877.
+
+ * testsuite.at: Add it.
+
+ * app_state.cc, app_state.hh, commands.cc, monotone.cc,
+ options.hh: Revert failed UI experiment: reenable logging merges
+ by default and rename --merges back to --no-merges.
+
+ * contrib/color-logs.{conf,sh}, contrib/monotone-notify.pl,
+ contrib/monotone.el, tests/t_log_nofiles_nomerges.at,
+ testsuite.at: Handle --no-merges.
+
+ * monotone.texi: Document --no-merges.
+
2006-02-23 Matt Johnston <matt@ucc.asn.au>
* enumerator.{cc,hh}: avoid transferring deltas on both sides of merge
@@ -15,6 +91,10 @@ 2006-02-21 Nathaniel Smith <njs@pobox.
2006-02-21 Nathaniel Smith <njs@pobox.com>
+ * roster_merge.cc: Fixup after merge.
+
+2006-02-21 Nathaniel Smith <njs@pobox.com>
+
* work.cc (detach_node): Check if we are passed the root dir, and
error out if so.
@@ -738,6 +818,17 @@ 2006-01-14 Nathaniel Smith <njs@pobox.
* keys.cc (require_password): Adjust accordingly.
* cert.cc (priv_key_exists, load_key_pair): Likewise.
+2006-01-14 Christof Petig <christof@petig-baender.de>
+
+ * database.cc, database.h: binary transparent infrastructure,
+ store and retrieve former base64 encoded columns as BLOBs
+
+ * schema_migration.cc: unbase64 changed columns, change comment
+ on files.data which indicates a different database format
+
+ * schema.sql: change comment on file which indicates, that
+ files.data is no longer base64 encoded
+
2006-01-14 Richard Levitte <richard@levitte.org>
* configure.ac: Make sure there's an empty xgettext.opts
============================================================
--- app_state.cc d6bd147ff69418001cff7cfd08e7ec18deca23ab
+++ app_state.cc 4990c26751504dded9cef9b1c6ffa66bef0d2b32
@@ -31,7 +31,7 @@ app_state::app_state()
app_state::app_state()
: branch_name(""), db(system_path()), keys(this), stdhooks(true),
rcfiles(true), diffs(false),
- merges(false), set_default(false), verbose(false), date_set(false),
+ no_merges(false), set_default(false), verbose(false), date_set(false),
search_root("/"),
depth(-1), last(-1), next(-1), diff_format(unified_diff), diff_args_provided(false),
use_lca(false), execute(false), bind_address(""), bind_port(""),
============================================================
--- app_state.hh 7fb16348486ca507f22a99d6aca9ba2dc4a658c0
+++ app_state.hh 03afbc7ba543f0b26f8ddf70d97c05e872cdb36b
@@ -40,7 +40,7 @@ public:
bool stdhooks;
bool rcfiles;
bool diffs;
- bool merges;
+ bool no_merges;
bool set_default;
bool verbose;
options_map options;
============================================================
--- commands.cc 8d15447176db8827209c2feeaaf0b0eaa7e2e1fd
+++ commands.cc 0fc12a37debd7db7812e2670afcb99d787f869e0
@@ -461,10 +461,11 @@ describe_revision(app_state & app, revis
return description;
}
+
static void
complete(app_state & app,
string const & str,
- revision_id & completion,
+ set<revision_id> & completion,
bool must_exist=true)
{
// This copies the start of selectors::parse_selector().to avoid
@@ -475,10 +476,10 @@ complete(app_state & app,
if (str.find_first_not_of(constants::legal_id_bytes) == string::npos
&& str.size() == constants::idlen)
{
- completion = revision_id(str);
+ completion.insert(revision_id(str));
if (must_exist)
- N(app.db.revision_exists(completion),
- F("no such revision '%s'") % completion);
+ N(app.db.revision_exists(*completion.begin()),
+ F("no such revision '%s'") % *completion.begin());
return;
}
@@ -494,16 +495,36 @@ complete(app_state & app,
N(completions.size() != 0,
F("no match for selection '%s'") % str);
+
+ for (set<string>::const_iterator i = completions.begin();
+ i != completions.end(); ++i)
+ {
+ pair<set<revision_id>::const_iterator, bool> p = completion.insert(revision_id(*i));
+ P(F("expanded to '%s'\n") % *(p.first));
+ }
+}
+
+
+static void
+complete(app_state & app,
+ string const & str,
+ revision_id & completion,
+ bool must_exist=true)
+{
+ set<revision_id> completions;
+
+ complete(app, str, completions, must_exist);
+
if (completions.size() > 1)
{
string err = (F("selection '%s' has multiple ambiguous expansions: \n") % str).str();
- for (set<string>::const_iterator i = completions.begin();
+ for (set<revision_id>::const_iterator i = completions.begin();
i != completions.end(); ++i)
- err += (describe_revision(app, revision_id(*i)) + "\n");
+ err += (describe_revision(app, *i) + "\n");
N(completions.size() == 1, i18n_format(err));
}
- completion = revision_id(*(completions.begin()));
- P(F("expanded to '%s'\n") % completion);
+
+ completion = *completions.begin();
}
@@ -1243,6 +1264,23 @@ ALIAS(mv, rename)
ALIAS(mv, rename)
+CMD(pivot_root, N_("workspace"), N_("NEW_ROOT PUT_OLD"),
+ N_("rename the root directory\n"
+ "after this command, the directory that currently has the name NEW_ROOT\n"
+ "will be the root directory, and the directory that is currently the root\n"
+ "directory will have name PUT_OLD.\n"
+ "Using --execute is strongly recommended."),
+ OPT_EXECUTE)
+{
+ if (args.size() != 2)
+ throw usage(name);
+
+ app.require_workspace();
+ file_path new_root = file_path_external(idx(args, 0));
+ file_path put_old = file_path_external(idx(args, 1));
+ perform_pivot_root(new_root, put_old, app);
+}
+
// fload and fmerge are simple commands for debugging the line
// merger.
@@ -1740,13 +1778,6 @@ ls_missing (app_state & app, vector<utf8
}
-struct lt_file_path
-{
- bool operator()(const file_path &fp1, const file_path &fp2) const
- {
- return fp1 < fp2;
- }
-};
static void
ls_changed (app_state & app, vector<utf8> const & args)
{
@@ -1754,7 +1785,7 @@ ls_changed (app_state & app, vector<utf8
revision_id rid;
roster_t old_roster, new_roster;
data tmp;
- std::set<file_path, lt_file_path> files;
+ std::set<file_path> files;
app.require_workspace();
get_working_revision_and_rosters(app, args, rs, old_roster, new_roster);
@@ -3410,7 +3441,11 @@ CMD(revert, N_("workspace"), N_("[PATH].
}
else
{
- mkdir_p(fp);
+ if (!directory_exists(fp))
+ {
+ P(F("recreating %s/") % fp);
+ mkdir_p(fp);
+ }
}
}
@@ -3542,7 +3577,7 @@ CMD(log, N_("informative"), N_("[FILE] .
CMD(log, N_("informative"), N_("[FILE] ..."),
N_("print history in reverse order (filtering by 'FILE'). If one or more\n"
"revisions are given, use them as a starting point."),
- OPT_LAST % OPT_NEXT % OPT_REVISION % OPT_BRIEF % OPT_DIFFS % OPT_MERGES %
+ OPT_LAST % OPT_NEXT % OPT_REVISION % OPT_BRIEF % OPT_DIFFS % OPT_NO_MERGES %
OPT_NO_FILES)
{
if (app.revision_selectors.size() == 0)
@@ -3563,11 +3598,11 @@ CMD(log, N_("informative"), N_("[FILE] .
for (std::vector<utf8>::const_iterator i = app.revision_selectors.begin();
i != app.revision_selectors.end(); i++)
{
- revision_id rid;
- complete(app, (*i)(), rid);
- frontier.insert(rid);
+ set<revision_id> rids;
+ complete(app, (*i)(), rids);
+ frontier.insert(rids.begin(), rids.end());
if (i == app.revision_selectors.begin())
- first_rid = rid;
+ first_rid = *rids.begin();
}
}
@@ -3690,7 +3725,7 @@ CMD(log, N_("informative"), N_("[FILE] .
inserter(next_frontier, next_frontier.end()));
}
- if (!app.merges && rev.is_merge_node())
+ if (app.no_merges && rev.is_merge_node())
print_this = false;
if (print_this)
============================================================
--- contrib/color-logs.conf ffe3e7270a2952c508db2f2d9c3df82e05c859f4
+++ contrib/color-logs.conf 87e8ceac1e0a8d173e2a0da01e659d048824e9ed
@@ -1,6 +1,6 @@
#
# this is a colorization config for reading the output of "monotone log"
-# or "monotone diff", or best of all "monotone log --diffs".
+# or "monotone diff", or best of all "monotone log --no-merges --diffs".
#
# use with the "colorize" script in this dir, or color-logs.sh
#
============================================================
--- contrib/color-logs.sh 90a0de6aa87b7f4b39f7947fd1d359a3cc936385
+++ contrib/color-logs.sh 4e04daeee4ee8ce8bf6ce45f074ba16faf50ccf9
@@ -1,5 +1,5 @@
#!/bin/sh
-./monotone log --diffs $@ \
+./monotone log --diffs --no-merges $@ \
| ./contrib/colorize -c contrib/color-logs.conf \
| less -r -p -----------------------------------------------------------------
============================================================
--- contrib/monotone-notify.pl aa93d7f9f601b51d607bd4d779e472067c41d5a2
+++ contrib/monotone-notify.pl d7f551f0f332f56785aaa59e99ade7400c8da84a
@@ -268,7 +268,7 @@ if ($mail || $debug) {
foreach my $revision (keys %revisions) {
$revision_data{$revision} =
[ map { chomp; $_ }
- my_backtick("$monotone$database log --last=1 --merges --revision=$revision") ];
+ my_backtick("$monotone$database log --last=1 --revision=$revision") ];
my $date = (split(' ', (grep(/^Date:/, @{$revision_data{$revision}}))[0]))[1];
if (defined $before && $date ge $before) {
@@ -582,7 +582,7 @@ sub revision_is_in_branch
if (!defined $$revision_data{$revision}) {
$$revision_data{$revision} =
[ map { chomp; $_ }
- my_backtick("$monotone$database log --last=1 --merges --revision=$revision") ];
+ my_backtick("$monotone$database log --last=1 --revision=$revision") ];
}
map {
============================================================
--- contrib/monotone.el 3dc1c23d499d1aa015ed7f145416a241a55f054f
+++ contrib/monotone.el 9e1a1ec218b98cd38c6126c48f00a1d585e65a13
@@ -686,7 +686,7 @@ the buffer if not global."
(when (eq 'tree (monotone-arg-decode arg))
(error "monotone subtree log is busted"))
;;
- (let ((cmds (list "log"))
+ (let ((cmds (list "log" "--no-merges"))
(depth monotone-log-depth))
(when (and (numberp depth) (< 0 depth))
(setq cmds (append cmds (list (format "--last=%d" depth)))))
============================================================
--- cset.cc a8497f9a82330f842cda2f242e97ef48e3a6b9fb
+++ cset.cc 5fdac8f01ad19e4a427e40aa4245026b534422f7
@@ -1072,56 +1072,76 @@ invalid_csets_test()
BOOST_CHECK_THROW(cs.apply_to(tree), std::logic_error);
}
{
- L(FL("TEST: can't rename root (for now)"));
+ L(FL("TEST: can't delete non-empty directory"));
setup_roster(r, f1, nis);
cset cs; MM(cs);
- split_path sp1, sp2;
- cs.dirs_added.insert(root);
- cs.nodes_renamed.insert(std::make_pair(root, baz));
+ cs.nodes_deleted.insert(foo);
BOOST_CHECK_THROW(cs.apply_to(tree), std::logic_error);
}
{
- L(FL("TEST: can't delete non-empty directory"));
- setup_roster(r, f1, nis);
+ L(FL("TEST: attach node with no root directory present"));
+ // for this test, make sure original roster has no contents
+ r = roster_t();
cset cs; MM(cs);
- cs.nodes_deleted.insert(foo);
+ split_path sp;
+ file_path_internal("blah/blah/blah").split(sp);
+ cs.dirs_added.insert(sp);
BOOST_CHECK_THROW(cs.apply_to(tree), std::logic_error);
}
{
- L(FL("TEST: can't delete root"));
- // for this test, make sure root has no contents
- r = roster_t();
+ L(FL("TEST: can't move a directory underneath itself"));
+ setup_roster(r, f1, nis);
cset cs; MM(cs);
- cs.nodes_deleted.insert(root);
+ split_path foo_blah;
+ file_path_internal("foo/blah").split(foo_blah);
+ cs.nodes_renamed.insert(std::make_pair(foo, foo_blah));
BOOST_CHECK_THROW(cs.apply_to(tree), std::logic_error);
}
+}
+
+void
+root_dir_test()
+{
+ temp_node_id_source nis;
+ roster_t r;
+ MM(r);
+ editable_roster_base tree(r, nis);
+
+ file_id f1(std::string("0000000000000000000000000000000000000001"));
+
+ split_path root, baz;
+ file_path().split(root);
+ file_path_internal("baz").split(baz);
+
{
- L(FL("TEST: can't delete and replace root"));
- // for this test, make sure root has no contents
- r = roster_t();
+ L(FL("TEST: can rename root"));
+ setup_roster(r, f1, nis);
cset cs; MM(cs);
- cs.nodes_deleted.insert(root);
+ split_path sp1, sp2;
cs.dirs_added.insert(root);
- BOOST_CHECK_THROW(cs.apply_to(tree), std::logic_error);
+ cs.nodes_renamed.insert(std::make_pair(root, baz));
+ cs.apply_to(tree);
+ r.check_sane(true);
}
{
- L(FL("TEST: attach node with no root directory present"));
+ L(FL("TEST: can delete root (but it makes us insane)"));
// for this test, make sure root has no contents
r = roster_t();
+ r.attach_node(r.create_dir_node(nis), root);
cset cs; MM(cs);
- split_path sp;
- file_path_internal("blah/blah/blah").split(sp);
- cs.dirs_added.insert(sp);
- BOOST_CHECK_THROW(cs.apply_to(tree), std::logic_error);
+ cs.nodes_deleted.insert(root);
+ cs.apply_to(tree);
+ BOOST_CHECK_THROW(r.check_sane(true), std::logic_error);
}
{
- L(FL("TEST: can't move a directory underneath itself"));
- setup_roster(r, f1, nis);
+ L(FL("TEST: can delete and replace root"));
+ r = roster_t();
+ r.attach_node(r.create_dir_node(nis), root);
cset cs; MM(cs);
- split_path foo_blah;
- file_path_internal("foo/blah").split(foo_blah);
- cs.nodes_renamed.insert(std::make_pair(foo, foo_blah));
- BOOST_CHECK_THROW(cs.apply_to(tree), std::logic_error);
+ cs.nodes_deleted.insert(root);
+ cs.dirs_added.insert(root);
+ cs.apply_to(tree);
+ r.check_sane(true);
}
}
@@ -1132,6 +1152,7 @@ add_cset_tests(test_suite * suite)
suite->add(BOOST_TEST_CASE(&basic_csets_test));
suite->add(BOOST_TEST_CASE(&invalid_csets_test));
suite->add(BOOST_TEST_CASE(&cset_written_test));
+ suite->add(BOOST_TEST_CASE(&root_dir_test));
}
#endif // BUILD_UNIT_TESTS
============================================================
--- database.cc 70d4d8f0c43de5e18bb023fc2c87805c0cdfa659
+++ database.cc 61bac503d11d0d68da007b53ec4a7f31e0453cdc
@@ -121,12 +121,6 @@ struct query
std::string sql_cmd;
};
-extern "C" {
-// some wrappers to ease migration
- const char *sqlite3_value_text_s(sqlite3_value *v);
- const char *sqlite3_column_text_s(sqlite3_stmt*, int col);
-}
-
database::database(system_path const & fn) :
filename(fn),
// nb. update this if you change the schema. unfortunately we are not
@@ -205,43 +199,18 @@ database::check_format()
}
}
-// sqlite3_value_text gives a const unsigned char * but most of the time
-// we need a signed char
-const char *
-sqlite3_value_text_s(sqlite3_value *v)
-{
- return (const char *)(sqlite3_value_text(v));
-}
-
-const char *
-sqlite3_column_text_s(sqlite3_stmt *stmt, int col)
-{
- return (const char *)(sqlite3_column_text(stmt, col));
-}
-
-static void
-sqlite3_unbase64_fn(sqlite3_context *f, int nargs, sqlite3_value ** args)
-{
- if (nargs != 1)
- {
- sqlite3_result_error(f, "need exactly 1 arg to unbase64()", -1);
- return;
- }
- data decoded;
- decode_base64(base64<data>(string(sqlite3_value_text_s(args[0]))), decoded);
- sqlite3_result_blob(f, decoded().c_str(), decoded().size(), SQLITE_TRANSIENT);
-}
-
static void
-sqlite3_unpack_fn(sqlite3_context *f, int nargs, sqlite3_value ** args)
+sqlite3_gunzip_fn(sqlite3_context *f, int nargs, sqlite3_value ** args)
{
if (nargs != 1)
{
- sqlite3_result_error(f, "need exactly 1 arg to unpack()", -1);
+ sqlite3_result_error(f, "need exactly 1 arg to gunzip()", -1);
return;
}
data unpacked;
- unpack(base64< gzip<data> >(string(sqlite3_value_text_s(args[0]))), unpacked);
+ const char *val = (const char*) sqlite3_value_blob(args[0]);
+ int bytes = sqlite3_value_bytes(args[0]);
+ decode_gzip(gzip<data>(std::string(val,val+bytes)), unpacked);
sqlite3_result_blob(f, unpacked().c_str(), unpacked().size(), SQLITE_TRANSIENT);
}
@@ -363,42 +332,49 @@ dump_request
struct
dump_request
{
- dump_request() {};
+ dump_request() : sql(), out() {};
struct sqlite3 *sql;
- string table_name;
ostream *out;
};
-static int
-dump_row_cb(void *data, int n, char **vals, char **cols)
+static void
+dump_row(std::ostream &out, sqlite3_stmt *stmt, std::string const& table_name)
{
- dump_request *dump = reinterpret_cast<dump_request *>(data);
- I(dump != NULL);
- I(vals != NULL);
- I(dump->out != NULL);
- *(dump->out) << boost::format("INSERT INTO %s VALUES(") % dump->table_name;
- for (int i = 0; i < n; ++i)
+ out << boost::format("INSERT INTO %s VALUES(") % table_name;
+ unsigned n = sqlite3_data_count(stmt);
+ for (unsigned i = 0; i < n; ++i)
{
if (i != 0)
- *(dump->out) << ',';
+ out << ',';
- if (vals[i] == NULL)
- *(dump->out) << "NULL";
- else
+ if (sqlite3_column_type(stmt, i) == SQLITE_BLOB)
{
- *(dump->out) << "'";
- for (char *cp = vals[i]; *cp; ++cp)
+ out << "X'";
+ const char *val = (const char*) sqlite3_column_blob(stmt, i);
+ int bytes = sqlite3_column_bytes(stmt, i);
+ out << encode_hexenc(std::string(val,val+bytes));
+ out << "'";
+ }
+ else
+ {
+ const unsigned char *val = sqlite3_column_text(stmt, i);
+ if (val == NULL)
+ out << "NULL";
+ else
{
- if (*cp == '\'')
- *(dump->out) << "''";
- else
- *(dump->out) << *cp;
+ out << "'";
+ for (const unsigned char *cp = val; *cp; ++cp)
+ {
+ if (*cp == '\'')
+ out << "''";
+ else
+ out << *cp;
+ }
+ out << "'";
}
- *(dump->out) << "'";
}
}
- *(dump->out) << ");\n";
- return 0;
+ out << ");\n";
}
static int
@@ -414,10 +390,24 @@ dump_table_cb(void *data, int n, char **
I(n == 3);
I(string(vals[1]) == "table");
*(dump->out) << vals[2] << ";\n";
- dump->table_name = string(vals[0]);
- string query = "SELECT * FROM " + string(vals[0]);
- sqlite3_exec(dump->sql, query.c_str(), dump_row_cb, data, NULL);
+ string table_name(vals[0]);
+ string query = "SELECT * FROM " + table_name;
+ sqlite3_stmt *stmt = 0;
+ sqlite3_prepare(dump->sql, query.c_str(), -1, &stmt, NULL);
assert_sqlite3_ok(dump->sql);
+
+ int stepresult = SQLITE_DONE;
+ do
+ {
+ stepresult = sqlite3_step(stmt);
+ I(stepresult == SQLITE_DONE || stepresult == SQLITE_ROW);
+ if (stepresult == SQLITE_ROW)
+ dump_row(*(dump->out), stmt, table_name);
+ }
+ while (stepresult == SQLITE_ROW);
+
+ sqlite3_finalize(stmt);
+ assert_sqlite3_ok(dump->sql);
return 0;
}
@@ -561,13 +551,14 @@ database::info(ostream & out)
% count("revision_ancestry")
% count("revision_certs")
// bytes
- % SPACE_USAGE("rosters", "id || data")
- % SPACE_USAGE("roster_deltas", "id || base || delta")
- % SPACE_USAGE("files", "id || data")
- % SPACE_USAGE("file_deltas", "id || base || delta")
- % SPACE_USAGE("revisions", "id || data")
- % SPACE_USAGE("revision_ancestry", "parent || child")
- % SPACE_USAGE("revision_certs", "hash || id || name || value || keypair || signature")
+ % SPACE_USAGE("rosters", "length(id) + length(data)")
+ % SPACE_USAGE("roster_deltas", "length(id) + length(base) + length(delta)")
+ % SPACE_USAGE("files", "length(id) + length(data)")
+ % SPACE_USAGE("file_deltas", "length(id) + length(base) + length(delta)")
+ % SPACE_USAGE("revisions", "length(id) + length(data)")
+ % SPACE_USAGE("revision_ancestry", "length(parent) + length(child)")
+ % SPACE_USAGE("revision_certs", "length(hash) + length(id) + length(name)"
+ " + length(value) + length(keypair) + length(signature)")
% total;
#undef SPACE_USAGE
@@ -732,9 +723,10 @@ database::fetch(results & res,
vector<string> row;
for (int col = 0; col < ncol; col++)
{
- const char * value = sqlite3_column_text_s(i->second.stmt(), col);
+ const char * value = (const char*)sqlite3_column_blob(i->second.stmt(), col);
+ int bytes = sqlite3_column_bytes(i->second.stmt(), col);
E(value, F("null result in query: %s\n") % query.sql_cmd);
- row.push_back(value);
+ row.push_back(std::string(value, value + bytes));
//L(FL("row %d col %d value='%s'\n") % nrow % col % value);
}
res.push_back(row);
@@ -843,12 +835,12 @@ unsigned long
}
unsigned long
-database::space_usage(string const & table, string const & concatenated_columns)
+database::space_usage(string const & table, string const & rowspace)
{
results res;
// COALESCE is required since SUM({empty set}) is NULL.
// the sqlite docs for SUM suggest this as a workaround
- query q("SELECT COALESCE(SUM(LENGTH(" + concatenated_columns + ")), 0) FROM " + table);
+ query q("SELECT COALESCE(SUM(" + rowspace + "), 0) FROM " + table);
fetch(res, one_col, one_row, q);
return lexical_cast<unsigned long>(res[0][0]);
}
@@ -876,9 +868,9 @@ database::get(hexenc<id> const & ident,
fetch(res, one_col, one_row, q % text(ident()));
// consistency check
- base64<gzip<data> > rdata(res[0][0]);
+ gzip<data> rdata(res[0][0]);
data rdata_unpacked;
- unpack(rdata, rdata_unpacked);
+ decode_gzip(rdata,rdata_unpacked);
hexenc<id> tid;
calculate_ident(rdata_unpacked, tid);
@@ -899,8 +891,8 @@ database::get_delta(hexenc<id> const & i
query q("SELECT delta FROM " + table + " WHERE id = ? AND base = ?");
fetch(res, one_col, one_row, q % text(ident()) % text(base()));
- base64<gzip<delta> > del_packed = res[0][0];
- unpack(del_packed, del);
+ gzip<delta> del_packed(res[0][0]);
+ decode_gzip(del_packed, del);
}
void
@@ -916,15 +908,14 @@ database::put(hexenc<id> const & ident,
MM(tid);
I(tid == ident);
- base64<gzip<data> > dat_packed;
- pack(dat, dat_packed);
-
+ gzip<data> dat_packed;
+ encode_gzip(dat, dat_packed);
uint32_t dat_size = dat_packed().size();
string insert = "INSERT INTO " + table + " VALUES(?, ?, ?)";
execute(query(insert)
% text(ident())
- % text(dat_packed())
+ % blob(dat_packed()));
% integer(dat_size));
}
void
@@ -938,8 +929,8 @@ database::put_delta(hexenc<id> const & i
I(!null_id(ident));
I(!null_id(base));
- base64<gzip<delta> > del_packed;
- pack(del, del_packed);
+ gzip<delta> del_packed;
+ encode_gzip(del, del_packed);
uint32_t del_size = del_packed().size();
@@ -947,7 +938,7 @@ database::put_delta(hexenc<id> const & i
execute(query(insert)
% text(ident())
% text(base())
- % text(del_packed())
+ % blob(del_packed()));
% integer(parent_distance + 1)
% integer(parent_size + del_size)
% integer(del_size));
@@ -1584,10 +1575,9 @@ database::get_revision(revision_id const
query("SELECT data FROM revisions WHERE id = ?")
% text(id.inner()()));
- base64<gzip<data> > rdat_packed;
- rdat_packed = base64<gzip<data> >(res[0][0]);
+ gzip<data> gzdata(res[0][0]);
data rdat;
- unpack(rdat_packed, rdat);
+ decode_gzip(gzdata,rdat);
// verify that we got a revision with the right id
{
@@ -1755,14 +1745,14 @@ database::put_revision(revision_id const
// Phase 3: Write the revision data
- base64<gzip<data> > d_packed;
- pack(d.inner(), d_packed);
+ gzip<data> d_packed;
+ encode_gzip(d.inner(), d_packed);
uint32_t d_size = d_packed().size();
execute(query("INSERT INTO revisions VALUES(?, ?, ?)")
% text(new_id.inner()())
- % text(d_packed())
+ % blob(d_packed()));
% integer(d_size));
for (edge_map::const_iterator e = rev.edges.begin();
@@ -1862,24 +1852,20 @@ database::delete_branch_named(cert_value
void
database::delete_branch_named(cert_value const & branch)
{
- base64<cert_value> encoded;
- encode_base64(branch, encoded);
L(FL("Deleting all references to branch %s\n") % branch);
execute(query("DELETE FROM revision_certs WHERE name='branch' AND value =?")
- % text(encoded()));
+ % blob(branch()));
execute(query("DELETE FROM branch_epochs WHERE branch=?")
- % text(encoded()));
+ % blob(branch()));
}
/// Deletes all certs referring to a particular tag.
void
database::delete_tag_named(cert_value const & tag)
{
- base64<cert_value> encoded;
- encode_base64(tag, encoded);
L(FL("Deleting all references to tag %s\n") % tag);
execute(query("DELETE FROM revision_certs WHERE name='tag' AND value =?")
- % text(encoded()));
+ % blob(tag()));
}
// crypto key management
@@ -1955,7 +1941,7 @@ database::get_pubkey(hexenc<id> const &
query("SELECT id, keydata FROM public_keys WHERE hash = ?")
% text(hash()));
id = res[0][0];
- pub_encoded = res[0][1];
+ encode_base64(rsa_pub_key(res[0][1]), pub_encoded);
}
void
@@ -1966,7 +1952,7 @@ database::get_key(rsa_keypair_id const &
fetch(res, one_col, one_row,
query("SELECT keydata FROM public_keys WHERE id = ?")
% text(pub_id()));
- pub_encoded = res[0][0];
+ encode_base64(rsa_pub_key(res[0][0]), pub_encoded);
}
void
@@ -1978,10 +1964,12 @@ database::put_key(rsa_keypair_id const &
I(!public_key_exists(thash));
E(!public_key_exists(pub_id),
F("another key with name '%s' already exists") % pub_id);
+ rsa_pub_key pub_key;
+ decode_base64(pub_encoded, pub_key);
execute(query("INSERT INTO public_keys VALUES(?, ?, ?)")
% text(thash())
% text(pub_id())
- % text(pub_encoded()));
+ % blob(pub_key()));
}
void
@@ -1998,6 +1986,10 @@ database::cert_exists(cert const & t,
string const & table)
{
results res;
+ cert_value value;
+ decode_base64(t.value, value);
+ rsa_sha1_signature sig;
+ decode_base64(t.sig, sig);
query q = query("SELECT id FROM " + table + " WHERE id = ? "
"AND name = ? "
"AND value = ? "
@@ -2005,10 +1997,10 @@ database::cert_exists(cert const & t,
"AND signature = ?")
% text(t.ident())
% text(t.name())
- % text(t.value())
+ % blob(value())
% text(t.key())
- % text(t.sig());
-
+ % blob(sig());
+
fetch(res, 1, any_rows, q);
I(res.size() == 0 || res.size() == 1);
@@ -2021,6 +2013,10 @@ database::put_cert(cert const & t,
{
hexenc<id> thash;
cert_hash_code(t, thash);
+ cert_value value;
+ decode_base64(t.value, value);
+ rsa_sha1_signature sig;
+ decode_base64(t.sig, sig);
string insert = "INSERT INTO " + table + " VALUES(?, ?, ?, ?, ?, ?)";
@@ -2028,9 +2024,9 @@ database::put_cert(cert const & t,
% text(thash())
% text(t.ident())
% text(t.name())
- % text(t.value())
+ % blob(value())
% text(t.key())
- % text(t.sig()));
+ % blob(sig()));
}
void
@@ -2041,11 +2037,15 @@ database::results_to_certs(results const
for (size_t i = 0; i < res.size(); ++i)
{
cert t;
+ base64<cert_value> value;
+ encode_base64(cert_value(res[i][2]), value);
+ base64<rsa_sha1_signature> sig;
+ encode_base64(rsa_sha1_signature(res[i][4]), sig);
t = cert(hexenc<id>(res[i][0]),
cert_name(res[i][1]),
- base64<cert_value>(res[i][2]),
+ value,
rsa_keypair_id(res[i][3]),
- base64<rsa_sha1_signature>(res[i][4]));
+ sig);
certs.push_back(t);
}
}
@@ -2054,14 +2054,10 @@ database::install_functions(app_state *
database::install_functions(app_state * app)
{
// register any functions we're going to use
- I(sqlite3_create_function(sql(), "unbase64", -1,
+ I(sqlite3_create_function(sql(), "gunzip", -1,
SQLITE_UTF8, NULL,
- &sqlite3_unbase64_fn,
+ &sqlite3_gunzip_fn,
NULL, NULL) == 0);
- I(sqlite3_create_function(sql(), "unpack", -1,
- SQLITE_UTF8, NULL,
- &sqlite3_unpack_fn,
- NULL, NULL) == 0);
}
void
@@ -2150,9 +2146,11 @@ database::get_certs(cert_name const & na
query q("SELECT id, name, value, keypair, signature FROM " + table +
" WHERE name = ? AND value = ?");
- fetch(res, 5, any_rows,
+ cert_value binvalue;
+ decode_base64(val, binvalue);
+ fetch(res, 5, any_rows,
q % text(name())
- % text(val()));
+ % blob(binvalue()));
results_to_certs(res, certs);
}
@@ -2168,10 +2166,12 @@ database::get_certs(hexenc<id> const & i
query q("SELECT id, name, value, keypair, signature FROM " + table +
" WHERE id = ? AND name = ? AND value = ?");
+ cert_value binvalue;
+ decode_base64(value, binvalue);
fetch(res, 5, any_rows,
q % text(ident())
% text(name())
- % text(value()));
+ % blob(binvalue()));
results_to_certs(res, certs);
}
@@ -2488,7 +2488,7 @@ void database::complete(selector_type ty
spot++;
certvalue = i->second.substr(spot);
lim += "SELECT id FROM revision_certs ";
- lim += (boost::format("WHERE name='%s' AND unbase64(value) glob '%s'")
+ lim += (boost::format("WHERE name='%s' AND CAST(value AS TEXT) glob '%s'")
% certname % certvalue).str();
}
else
@@ -2507,7 +2507,7 @@ void database::complete(selector_type ty
% author_cert_name
% tag_cert_name
% branch_cert_name).str();
- lim += (boost::format(" AND unbase64(value) glob '*%s*'")
+ lim += (boost::format(" AND CAST(value AS TEXT) glob '*%s*'")
% i->second).str();
}
else if (i->first == selectors::sel_head)
@@ -2521,15 +2521,13 @@ void database::complete(selector_type ty
}
else
{
- string subquery = (boost::format("SELECT DISTINCT value FROM revision_certs WHERE name='%s' and unbase64(value) glob '%s'")
+ string subquery = (boost::format("SELECT DISTINCT value FROM revision_certs WHERE name='%s' and CAST(value AS TEXT) glob '%s'")
% branch_cert_name % i->second).str();
results res;
fetch(res, one_col, any_rows, query(subquery));
for (size_t i = 0; i < res.size(); ++i)
{
- base64<data> row_encoded(res[i][0]);
- data row_decoded;
- decode_base64(row_encoded, row_decoded);
+ data row_decoded(res[i][0]);
branch_names.push_back(row_decoded());
}
}
@@ -2568,8 +2566,7 @@ void database::complete(selector_type ty
if ((i->first == selectors::sel_branch) && (i->second.size() == 0))
{
__app->require_workspace("the empty branch selector b: refers to the current branch");
- // FIXME: why do we have to glob on the unbase64(value), rather than being able to use == ?
- lim += (boost::format("SELECT id FROM revision_certs WHERE name='%s' AND unbase64(value) glob '%s'")
+ lim += (boost::format("SELECT id FROM revision_certs WHERE name='%s' AND CAST(value AS TEXT) glob '%s'")
% branch_cert_name % __app->branch_name).str();
L(FL("limiting to current branch '%s'\n") % __app->branch_name);
}
@@ -2579,13 +2576,13 @@ void database::complete(selector_type ty
switch (i->first)
{
case selectors::sel_earlier:
- lim += (boost::format("unbase64(value) <= X'%s'") % encode_hexenc(i->second)).str();
+ lim += (boost::format("value <= X'%s'") % encode_hexenc(i->second)).str();
break;
case selectors::sel_later:
- lim += (boost::format("unbase64(value) > X'%s'") % encode_hexenc(i->second)).str();
+ lim += (boost::format("value > X'%s'") % encode_hexenc(i->second)).str();
break;
default:
- lim += (boost::format("unbase64(value) glob '%s%s%s'")
+ lim += (boost::format("CAST(value AS TEXT) glob '%s%s%s'")
% prefix % i->second % suffix).str();
break;
}
@@ -2626,7 +2623,7 @@ void database::complete(selector_type ty
(boost::format(" (name='%s')") % certname).str();
}
- query_str += (boost::format(" AND (unbase64(value) GLOB '%s%s%s')")
+ query_str += (boost::format(" AND (CAST(value AS TEXT) GLOB '%s%s%s')")
% prefix % partial % suffix).str();
query_str += (boost::format(" AND (id IN %s)") % lim).str();
}
@@ -2639,9 +2636,7 @@ void database::complete(selector_type ty
completions.insert(res[i][0]);
else
{
- base64<data> row_encoded(res[i][0]);
- data row_decoded;
- decode_base64(row_encoded, row_decoded);
+ data row_decoded(res[i][0]);
completions.insert(row_decoded());
}
}
@@ -2657,9 +2652,7 @@ database::get_epochs(std::map<cert_value
fetch(res, 2, any_rows, query("SELECT branch, epoch FROM branch_epochs"));
for (results::const_iterator i = res.begin(); i != res.end(); ++i)
{
- base64<cert_value> encoded(idx(*i, 0));
- cert_value decoded;
- decode_base64(encoded, decoded);
+ cert_value decoded(idx(*i, 0));
I(epochs.find(decoded) == epochs.end());
epochs.insert(std::make_pair(decoded, epoch_data(idx(*i, 1))));
}
@@ -2676,8 +2669,7 @@ database::get_epoch(epoch_id const & eid
" WHERE hash = ?")
% text(eid.inner()()));
I(res.size() == 1);
- base64<cert_value> encoded(idx(idx(res, 0), 0));
- decode_base64(encoded, branch);
+ branch = cert_value(idx(idx(res, 0), 0));
epo = epoch_data(idx(idx(res, 0), 1));
}
@@ -2696,23 +2688,19 @@ database::set_epoch(cert_value const & b
database::set_epoch(cert_value const & branch, epoch_data const & epo)
{
epoch_id eid;
- base64<cert_value> encoded;
- encode_base64(branch, encoded);
epoch_hash_code(branch, epo, eid);
I(epo.inner()().size() == constants::epochlen);
execute(query("INSERT OR REPLACE INTO branch_epochs VALUES(?, ?, ?)")
% text(eid.inner()())
- % text(encoded())
+ % blob(branch())
% text(epo.inner()()));
}
void
database::clear_epoch(cert_value const & branch)
{
- base64<cert_value> encoded;
- encode_base64(branch, encoded);
execute(query("DELETE FROM branch_epochs WHERE branch = ?")
- % text(encoded()));
+ % blob(branch()));
}
// vars
@@ -2726,12 +2714,8 @@ database::get_vars(std::map<var_key, var
for (results::const_iterator i = res.begin(); i != res.end(); ++i)
{
var_domain domain(idx(*i, 0));
- base64<var_name> name_encoded(idx(*i, 1));
- var_name name;
- decode_base64(name_encoded, name);
- base64<var_value> value_encoded(idx(*i, 2));
- var_value value;
- decode_base64(value_encoded, value);
+ var_name name(idx(*i, 1));
+ var_value value(idx(*i, 2));
I(vars.find(std::make_pair(domain, name)) == vars.end());
vars.insert(std::make_pair(std::make_pair(domain, name), value));
}
@@ -2761,24 +2745,18 @@ database::set_var(var_key const & key, v
void
database::set_var(var_key const & key, var_value const & value)
{
- base64<var_name> name_encoded;
- encode_base64(key.second, name_encoded);
- base64<var_value> value_encoded;
- encode_base64(value, value_encoded);
execute(query("INSERT OR REPLACE INTO db_vars VALUES(?, ?, ?)")
% text(key.first())
- % text(name_encoded())
- % text(value_encoded()));
+ % blob(key.second())
+ % blob(value()));
}
void
database::clear_var(var_key const & key)
{
- base64<var_name> name_encoded;
- encode_base64(key.second, name_encoded);
execute(query("DELETE FROM db_vars WHERE domain = ? AND name = ?")
% text(key.first())
- % text(name_encoded()));
+ % blob(key.second()));
}
// branches
@@ -2792,10 +2770,7 @@ database::get_branches(vector<string> &
fetch(res, one_col, any_rows, q % text(cert_name));
for (size_t i = 0; i < res.size(); ++i)
{
- base64<data> row_encoded(res[i][0]);
- data name;
- decode_base64(row_encoded, name);
- names.push_back(name());
+ names.push_back(res[i][0]);
}
}
@@ -2906,7 +2881,7 @@ database::put_roster(revision_id const &
get_version(old_id, old_data, data_table, delta_table);
delta del;
diff(old_data, new_data, del);
- put_version(old_id, new_id, del, new_data, data_table, delta_table);
+ put_delta(new_id, old_id, del, delta_table);
delta_written = true;
break;
}
============================================================
--- file_io.cc 3214c2cad3ec630d8466926bd4bae693de9184a0
+++ file_io.cc 3ca8050b61b62ef9010b0ebfda755a0af9269104
@@ -347,15 +347,15 @@ read_localized_data(file_path const & pa
dat = tmp2;
}
-void read_directory(system_path const & path,
+void read_directory(any_path const & path,
std::vector<utf8> & files,
std::vector<utf8> & dirs)
{
files.clear();
dirs.clear();
fs::directory_iterator ei;
- for(fs::directory_iterator di(path.as_external());
- di != ei; ++di)
+ for (fs::directory_iterator di(system_path(path).as_external());
+ di != ei; ++di)
{
fs::path entry = *di;
if (!fs::exists(entry)
@@ -363,6 +363,8 @@ void read_directory(system_path const &
|| di->string() == "..")
continue;
+ // FIXME: BUG: this screws up charsets (assumes blindly that the fs is
+ // utf8)
if (fs::is_directory(entry))
dirs.push_back(utf8(entry.leaf()));
else
@@ -484,8 +486,6 @@ write_data(system_path const & path,
{
write_data_impl(path, data, tmpdir / (boost::format("data.tmp.%d") %
get_process_id()).str());
-
-
}
tree_walker::~tree_walker() {}
============================================================
--- file_io.hh 2082dc3c8480400f32fcbe1c4d881d7512de2204
+++ file_io.hh 362691f10f63d93e7cf83f299fe5aa0b4dcbee17
@@ -72,7 +72,7 @@ void read_localized_data(file_path const
data & dat,
lua_hooks & lua);
-void read_directory(system_path const & path,
+void read_directory(any_path const & path,
std::vector<utf8> & files,
std::vector<utf8> & dirs);
@@ -101,6 +101,7 @@ public:
class tree_walker
{
public:
+ // returns true if the directory should be descended into
virtual void visit_dir(file_path const & path);
virtual void visit_file(file_path const & path) = 0;
virtual ~tree_walker();
============================================================
--- monotone.cc 6626e22d6ef4d9c8d3380a2f498599dd57bc6d3d
+++ monotone.cc 29890d9e90e828fa96d845cb881bb024a8267d99
@@ -60,7 +60,7 @@ struct poptOption coptions[] =
{"pid-file", 0, POPT_ARG_STRING, &argstr, OPT_PIDFILE, gettext_noop("record process id of server"), NULL},
{"brief", 0, POPT_ARG_NONE, NULL, OPT_BRIEF, gettext_noop("print a brief version of the normal output"), NULL},
{"diffs", 0, POPT_ARG_NONE, NULL, OPT_DIFFS, gettext_noop("print diffs along with logs"), NULL},
- {"merges", 0, POPT_ARG_NONE, NULL, OPT_MERGES, gettext_noop("include merges when printing logs"), NULL},
+ {"no-merges", 0, POPT_ARG_NONE, NULL, OPT_NO_MERGES, gettext_noop("exclude merges when printing logs"), NULL},
{"set-default", 0, POPT_ARG_NONE, NULL, OPT_SET_DEFAULT, gettext_noop("use the current arguments as the future default"), NULL},
{"exclude", 0, POPT_ARG_STRING, &argstr, OPT_EXCLUDE, gettext_noop("leave out anything described by its argument"), NULL},
{"unified", 0, POPT_ARG_NONE, NULL, OPT_UNIFIED_DIFF, gettext_noop("use unified diff format"), NULL},
@@ -426,8 +426,8 @@ cpp_main(int argc, char ** argv)
app.diffs = true;
break;
- case OPT_MERGES:
- app.merges = true;
+ case OPT_NO_MERGES:
+ app.no_merges = true;
break;
case OPT_SET_DEFAULT:
============================================================
--- monotone.texi 1fcc35f2ac3ca9ba692509cd29f6f5ff01b6616a
+++ monotone.texi d62e740d5bf36c317e4ec3fea155132bd7ba702d
@@ -34,7 +34,7 @@
@page
@vskip 0pt plus 1filll
Copyright @copyright{} 2003, 2004 Graydon Hoare
-Copyright @copyright{} 2004, 2005 Nathaniel Smith
+Copyright @copyright{} 2004, 2005, 2006 Nathaniel Smith
Copyright @copyright{} 2005 Derek Scherger
Copyright @copyright{} 2005 Daniel Carosone
All rights reserved
@@ -3186,7 +3186,7 @@ @section File Attributes
quoted value for that attribute. Stanzas are separated by blank lines.
As a convenience, you can use the @code{monotone attr} command to set
-and view the values of these attributes; see @ref{Working Copy}.
+and view the values of these attributes; see @ref{Workspace}.
You can tell monotone to automatically take actions based on these
attributes by defining hooks; see the @code{attr_functions} entry in
@@ -3421,7 +3421,7 @@ @heading Incorporating New Changes
examine descendents of your base revision, and ignore other heads on
your branch.
-@heading Moving Working Copy to Another Revision
+@heading Moving Workspace to Another Revision
@multitable @columnfractions .4 .4
@item
@@ -3487,7 +3487,7 @@ @heading Viewing Differences
@emph{revision IDs}, rather than file IDs. If one leaves off the file
argument, then diff can print the difference between two entire trees.
-@heading Showing Working Copy Status
+@heading Showing Workspace Status
@multitable @columnfractions .4 .4
@item
@@ -3508,7 +3508,7 @@ @heading Showing Working Copy Status
difference is that monotone's @command{status} command always gives a
status of the whole tree, and outputs a more compact summary than CVS.
-@heading Adding Directories and Files to Working Copy
+@heading Adding Directories and Files to Workspace
@multitable @columnfractions .4 .4
@item
@@ -3532,7 +3532,7 @@ @heading Adding Directories and Files to
Directories are created as needed, and empty directories are ignored.
-@heading Removing Directories and Files from Working Copy
+@heading Removing Directories and Files from Workspace
@multitable @columnfractions .4 .4
@item
@@ -3631,7 +3631,7 @@ @chapter Command Reference
@menu
* Tree:: Operations on tree states in your database
-* Working Copy:: Operations on your workspace
+* Workspace:: Operations on your workspace
* Network:: Communication with the network
* Informative:: Production of descriptive reports
* Key and Cert:: General operations on keys or certificates
@@ -3790,8 +3790,8 @@ @section Tree
@page
-@node Working Copy
-@section Working Copy
+@node Workspace
+@section Workspace
@ftable @command
@item monotone setup [@var{directory}]
@@ -3826,7 +3826,7 @@ @section Working Copy
any added entries inserted in its manifest.
-@item monotone drop @var{pathname...}
+@item monotone [--execute] drop @var{pathname...}
@itemx monotone drop --missing
This command places ``drop'' entries for the paths specified in
@var{pathname...} in the workspace's ``work list''. The work list of
@@ -3850,6 +3850,10 @@ @section Working Copy
you should run @command{drop}, and then perform the actual delete using
whatever mechanism you normally use to delete files.
+The option @option{--execute} will make ``drop'' perform the actual
+deletion operations in the filesystem. It will ignore files or
+directories which have already been deleted.
+
@item monotone [--execute] rename @var{src} @var{dst}
@itemx monotone [--execute] rename @var{src1} @var{...} @var{dst/}
This command places ``rename'' entries for the paths specified in
@@ -4012,6 +4016,35 @@ @section Working Copy
in inodeprints mode, and that the inodeprints cache is accurate and up
to date.
+@item monotone pivot_root [--execute] pivot_root @var{new_root} @var{put_old}
+Most users will never need this command. It is primarily useful in
+certain tricky cases where one wishes to combine several projects
+into one, or split one project into several.
+
+Its effect is to rename the directory whose name is currently
+@var{new_root} to become the root directory of the versioned tree, and
+to at the same time rename the directory that is currently the root of
+the versioned tree to have the name @var{put_old}. Conceptually, it
+is equivalent to executing the following commands in the root of the
+workspace:
+
+@smallexample
+@group
+$ monotone rename . @var{new_root}/@var{put_old}
+$ monotone rename @var{new_root} .
+@end group
+@end smallexample
+
+Except, of course, that these @command{rename} commands are illegal,
+because after the first command the tree has no root at all, and there
+is a directory loop. This illegality is the only reason for
+@command{pivot_root}'s existence; internally, the result is treated
+exactly like two renames, including with respect to merges and
+updates.
+
+The use of @option{--execute} with this command is strongly
+recommended, though not required.
+
@end ftable
@page
@@ -4139,7 +4172,7 @@ @section Informative
to files changed within the current subdirectory of the workspace.
@item monotone log
-@itemx monotone log [--last=@var{n}] [--next=@var{n}] [--revision=@var{id} [...]] [--brief] [--merges] [--no-files] [--diffs] [@var{file} [...]]
+@itemx monotone log [--last=@var{n}] [--next=@var{n}] [--revision=@var{id} [...]] [--brief] [--no-merges] [--no-files] [--diffs] [@var{file} [...]]
This command prints out a log, in reverse-ancestry order, of small
history summaries. Each summary contains author, date, changelog and
@@ -4157,9 +4190,9 @@ @section Informative
revision in forward-ancestry order. This is useful to review changes
that will be applied to the workspace when @command{update} is run.
-By default, the log entries for merge nodes are not shown; usually
-they don't contain much interesting information. If @code{--merges} is
-given, the log entries for these nodes will be included.
+By default, the log entries for merge nodes are shown. If
+@code{--no-merges} is given, the log entries for these nodes will be
+excluded.
If @code{--no-files} is given, the log output excludes the list of
files changed in each revision.
============================================================
--- netcmd.cc 5a63ccd88ddb02cf5853e13ce3fff6ea20851a53
+++ netcmd.cc da3773c93069c0834ce0b3caf34020305dd7d8b2
@@ -88,15 +88,6 @@ netcmd::read(string_queue & inbuf, chain
return false;
u8 extracted_ver = extract_datum_lsb<u8>(inbuf, pos, "netcmd protocol number");
- if (extracted_ver != version)
- throw bad_decode(F("protocol version mismatch: wanted '%d' got '%d'\n"
- "%s")
- % widen<u32,u8>(version)
- % widen<u32,u8>(extracted_ver)
- % ((version < extracted_ver)
- ? _("the remote side has a newer, incompatible version of monotone")
- : _("the remote side has an older, incompatible version of monotone")));
- version = extracted_ver;
u8 cmd_byte = extract_datum_lsb<u8>(inbuf, pos, "netcmd code");
switch (cmd_byte)
@@ -115,8 +106,21 @@ netcmd::read(string_queue & inbuf, chain
cmd_code = static_cast<netcmd_code>(cmd_byte);
break;
default:
- throw bad_decode(F("unknown netcmd code 0x%x") % widen<u32,u8>(cmd_byte));
+ // if the versions don't match, we will throw the more descriptive
+ // error immediately after this switch.
+ if (extracted_ver == version)
+ throw bad_decode(F("unknown netcmd code 0x%x")
+ % widen<u32,u8>(cmd_byte));
}
+ // Ignore the version on usher_cmd packets.
+ if (extracted_ver != version && cmd_code != usher_cmd)
+ throw bad_decode(F("protocol version mismatch: wanted '%d' got '%d'\n"
+ "%s")
+ % widen<u32,u8>(version)
+ % widen<u32,u8>(extracted_ver)
+ % ((version < extracted_ver)
+ ? _("the remote side has a newer, incompatible version of monotone")
+ : _("the remote side has an older, incompatible version of monotone")));
// check to see if we have even enough bytes for a complete uleb128
size_t payload_len = 0;
============================================================
--- netcmd.hh 22664387cea0916b87288113ec5b559c2c49eda5
+++ netcmd.hh e290b45f5acb01bfe181832d4750275e05b2f98f
@@ -69,9 +69,7 @@ public:
std::string payload;
public:
netcmd();
- netcmd(u8 _version);
netcmd_code get_cmd_code() const {return cmd_code;}
- u8 get_version() const {return version;}
size_t encoded_size();
bool operator==(netcmd const & other) const;
============================================================
--- options.hh 16194449c59ae0307ab9bbf15ae879f0f8063fdd
+++ options.hh 216cb82f6f82b63b0f1535b39bb985a237b43359
@@ -32,7 +32,7 @@
#define OPT_MSGFILE 23
#define OPT_BRIEF 24
#define OPT_DIFFS 25
-#define OPT_MERGES 26
+#define OPT_NO_MERGES 26
#define OPT_LAST 27
#define OPT_NEXT 28
#define OPT_VERBOSE 29
============================================================
--- paths.cc c13e9b0c44a37a70e6c7e6d5c8b8869e363ccab9
+++ paths.cc 05c27908836d28a468070bb8e7a808417b8401f1
@@ -76,6 +76,7 @@ bookkeeping_path const bookkeeping_root(
static access_tracker<system_path> working_root;
bookkeeping_path const bookkeeping_root("MT");
+path_component const bookkeeping_root_component("MT");
void
save_initial_path()
@@ -438,13 +439,19 @@ system_path::system_path(any_path const
system_path::system_path(any_path const & other, bool in_true_workspace)
{
- I(!is_absolute_here(other.as_internal()));
- system_path wr;
- if (in_true_workspace)
- wr = working_root.get();
+ if (is_absolute_here(other.as_internal()))
+ // another system_path. the normalizing isn't really necessary, but it
+ // makes me feel warm and fuzzy.
+ data = normalize_out_dots(other.as_internal());
else
- wr = working_root.get_but_unused();
- data = normalize_out_dots((wr / other.as_internal()).as_internal());
+ {
+ system_path wr;
+ if (in_true_workspace)
+ wr = working_root.get();
+ else
+ wr = working_root.get_but_unused();
+ data = normalize_out_dots((wr / other.as_internal()).as_internal());
+ }
}
static inline std::string const_system_path(utf8 const & path)
@@ -468,6 +475,26 @@ system_path::system_path(utf8 const & pa
}
///////////////////////////////////////////////////////////////////////////
+// utility
+///////////////////////////////////////////////////////////////////////////
+
+void
+dirname_basename(split_path const & sp,
+ split_path & dirname, path_component & basename)
+{
+ I(!sp.empty());
+ // L(FL("dirname_basename('%s' [%d components],...)\n") % file_path(sp) % sp.size());
+ dirname = sp;
+ dirname.pop_back();
+ basename = sp.back();
+ if (dirname.empty())
+ {
+ // L(FL("basename %d vs. null component %d\n") % basename % the_null_component);
+ I(null_name(basename));
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
// workspace (and path root) handling
///////////////////////////////////////////////////////////////////////////
@@ -825,6 +852,7 @@ static void test_split_join()
split_path split_mt1, split_mt2;
file_path_internal("foo/MT").split(split_mt1);
BOOST_CHECK(split_mt1.size() == 3);
+ I(split_mt1[2] == bookkeeping_root_component);
split_mt2.push_back(the_null_component);
split_mt2.push_back(split_mt1[2]);
// split_mt2 now contains the component "MT"
============================================================
--- paths.hh 054a74b153b42a34140f2776f468bf79c844fa64
+++ paths.hh e81d1f0e7efdbff539b8b92f04ad357770130fd4
@@ -207,6 +207,7 @@ extern bookkeeping_path const bookkeepin
};
extern bookkeeping_path const bookkeeping_root;
+extern path_component const bookkeeping_root_component;
// this will always be an absolute path
class system_path : public any_path
@@ -234,6 +235,9 @@ public:
system_path operator /(std::string const & to_append) const;
};
+void
+dirname_basename(split_path const & sp,
+ split_path & dirname, path_component & basename);
void
save_initial_path();
============================================================
--- roster.cc 5313de9037e0af779b593f9f432155891a70374a
+++ roster.cc ccbdfd50a2a99c49598ae638a013a095f232c876
@@ -305,23 +305,7 @@ roster_t::operator=(roster_t const & oth
return *this;
}
-void
-dirname_basename(split_path const & sp,
- split_path & dirname, path_component & basename)
-{
- I(!sp.empty());
- // L(FL("dirname_basename('%s' [%d components],...)\n") % file_path(sp) % sp.size());
- split_path::const_iterator penultimate = sp.begin() + (sp.size()-1);
- dirname = split_path(sp.begin(), penultimate);
- basename = *penultimate;
- if (dirname.empty())
- {
- // L(FL("basename %d vs. null component %d\n") % basename % the_null_component);
- I(null_name(basename));
- }
-}
-
struct
dfs_iter
{
@@ -612,13 +596,10 @@ roster_t::detach_node(split_path const &
path_component basename;
dirname_basename(pth, dirname, basename);
+ I(has_root());
if (dirname.empty())
{
// detaching the root dir
- {
- // detaching the root dir is currently forbidden.
- I(false);
- }
I(null_name(basename));
node_id root_id = root_dir->self;
safe_insert(old_locations,
============================================================
--- roster.hh 0647777b7cab5a2c17419998351f049eadc706d5
+++ roster.hh 9ec5d3bbd5751f987a7591a3d577002a627a36e3
@@ -32,11 +32,6 @@ typedef boost::shared_ptr<dir_node> dir_
typedef boost::shared_ptr<file_node> file_t;
typedef boost::shared_ptr<dir_node> dir_t;
-// FIXME: perhaps move this to paths.{cc,hh}
-void
-dirname_basename(split_path const & sp,
- split_path & dirname, path_component & basename);
-
node_id const the_null_node = 0;
inline bool
============================================================
--- roster_merge.cc aa38469bceafec9e94d2ba9c291cf08d6fc90e06
+++ roster_merge.cc d1d307d2cc0fac8f4c50963b1563edcc3df26d86
@@ -25,7 +25,9 @@ roster_merge_result::is_clean_except_for
&& node_attr_conflicts.empty()
&& orphaned_node_conflicts.empty()
&& rename_target_conflicts.empty()
- && directory_loop_conflicts.empty();
+ && directory_loop_conflicts.empty()
+ && illegal_name_conflicts.empty()
+ && !missing_root_dir;
}
void
@@ -81,6 +83,12 @@ roster_merge_result::log_conflicts()
% directory_loop_conflicts[i].nid
% directory_loop_conflicts[i].parent_name.first
% directory_loop_conflicts[i].parent_name.second);
+
+ for (size_t i = 0; i < illegal_name_conflicts.size(); ++i)
+ L(FL("illegal name conflict: node %d, wanted parent %d, name %s")
+ % illegal_name_conflicts[i].nid
+ % illegal_name_conflicts[i].parent_name.first
+ % illegal_name_conflicts[i].parent_name.second);
}
void
@@ -121,6 +129,12 @@ roster_merge_result::warn_non_content_co
% directory_loop_conflicts[i].nid
% directory_loop_conflicts[i].parent_name.first
% directory_loop_conflicts[i].parent_name.second);
+
+ for (size_t i = 0; i < illegal_name_conflicts.size(); ++i)
+ W(F("illegal name conflict: node %d, wanted parent %d, name %s")
+ % illegal_name_conflicts[i].nid
+ % illegal_name_conflicts[i].parent_name.first
+ % illegal_name_conflicts[i].parent_name.second);
}
void
@@ -132,6 +146,8 @@ roster_merge_result::clear()
orphaned_node_conflicts.clear();
rename_target_conflicts.clear();
directory_loop_conflicts.clear();
+ illegal_name_conflicts.clear();
+ missing_root_dir = false;
roster = roster_t();
}
@@ -533,6 +549,29 @@ roster_merge(roster_t const & left_paren
I(right_mi == right_markings.end());
I(new_i == result.roster.all_nodes().end());
}
+
+ // now check for the possible global problems
+ if (!result.roster.has_root())
+ result.missing_root_dir = true;
+ else
+ {
+ // we can't have an illegal MT dir unless we have a root node in the
+ // first place...
+ split_path bookkeeping_root_split;
+ bookkeeping_root_split.push_back(the_null_component);
+ bookkeeping_root_split.push_back(bookkeeping_root_component);
+ if (result.roster.has_node(bookkeeping_root_split))
+ {
+ illegal_name_conflict conflict;
+ node_t n = result.roster.get_node(bookkeeping_root_split);
+ conflict.nid = n->self;
+ conflict.parent_name.first = n->parent;
+ conflict.parent_name.second = n->name;
+ I(n->name == bookkeeping_root_component);
+ I(n->self == result.roster.detach_node(bookkeeping_root_split));
+ result.illegal_name_conflicts.push_back(conflict);
+ }
+ }
}
#ifdef BUILD_UNIT_TESTS
@@ -562,23 +601,28 @@ roster_merge(roster_t const & left_paren
// node attr, file and dir
//
// attr lifecycle:
-// seen in both -- -->mark merge cases
-// live in one and unseen in other
-// dead in one and unseen in other
+// seen in both -->mark merge cases, above
+// live in one and unseen in other -->live
+// dead in one and unseen in other -->dead
//
// two diff nodes with same name
// directory loops
// orphans
// name collision on root dir
+// illegal node ("MT")
+// missing root dir
//
// interactions:
// in-node name conflict + possible between-node name conflict
// in-node name conflict + both possible names orphaned
// in-node name conflict + directory loop conflict
+// in-node name conflict + one name illegal
// between-node name conflict + both nodes orphaned
// between-node name conflict + both nodes cause loop
+// between-node name conflict + both nodes illegal
-// need roster, marking, birth revs, and uncommon ancestors for each side...
+// to run roster_merge, need roster, marking, birth revs, and uncommon
+// ancestors for each side...
namespace
{
============================================================
--- roster_merge.hh 9227745f9aeb67c68ca363dc1df62537c8bcb873
+++ roster_merge.hh 3a86138ac40adb1f2736fc9f348988b91aea2ff4
@@ -93,10 +93,19 @@ struct directory_loop_conflict
std::pair<node_id, path_component> parent_name;
};
-// renaming the root dir (as we currently do _not_) allows:
+// renaming the root dir allows these:
// -- MT in root
// -- missing root directory
+// this is a node that cleanly merged to some name, but that name was somehow
+// forbidden. (Currently, the only forbidden name is "MT" in the root
+// directory.)
+struct illegal_name_conflict
+{
+ node_id nid;
+ std::pair<node_id, path_component> parent_name;
+};
+
struct roster_merge_result
{
std::vector<node_name_conflict> node_name_conflicts;
@@ -105,6 +114,8 @@ struct roster_merge_result
std::vector<orphaned_node_conflict> orphaned_node_conflicts;
std::vector<rename_target_conflict> rename_target_conflicts;
std::vector<directory_loop_conflict> directory_loop_conflicts;
+ std::vector<illegal_name_conflict> illegal_name_conflicts;
+ bool missing_root_dir;
// this roster is sane if is_clean() returns true
roster_t roster;
bool is_clean();
============================================================
--- schema.sql 5e315b54e2c1df1f315c3aff2ad9a551332debb7
+++ schema.sql c68ba3a5f158efdf6cae10d6b307a9cf0d35be44
@@ -22,15 +22,15 @@ CREATE TABLE files
CREATE TABLE files
(
id primary key, -- strong hash of file contents
- data not null, -- compressed, encoded contents of a file
+ data not null -- compressed contents of a file
size integer not null -- length(data)
);
CREATE TABLE file_deltas
- (
- id not null, -- strong hash of file contents
- base not null, -- joins with files.id or file_deltas.id
- delta not null, -- rdiff to construct current from base
+ (
+ id not null, -- strong hash of file contents
+ base not null, -- joins with files.id or file_deltas.id
+ delta not null, -- compressed rdiff to construct current from base
path_dist integer not null, -- 1 if base is full, otherwise path_dist(base)+1
path_size integer not null, -- size + size of base
size integer not null, -- length(delta)
============================================================
--- schema_migration.cc 9f3a9b8a4a509edf8af01c796cbc6588e902e888
+++ schema_migration.cc 7d215b15eb77f65457092c0cc1553f4ab2689a4e
@@ -20,6 +20,7 @@
#include "botan/botan.h"
#include "app_state.hh"
#include "keys.hh"
+#include "transforms.hh"
// this file knows how to migrate schema databases. the general strategy is
// to hash each schema we ever use, and make a list of the SQL commands
@@ -54,12 +55,8 @@ typedef boost::tokenizer<boost::char_sep
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
-extern "C" {
- const char *sqlite3_value_text_s(sqlite3_value *v);
-}
-
static string
-lowercase(string const & in)
+lowercase_facet(string const & in)
{
I(40==in.size());
const int sz=40;
@@ -93,7 +90,7 @@ calculate_id(string const & in,
Botan::Pipe p(new Botan::Hash_Filter("SHA-1"), new Botan::Hex_Encoder());
p.process_msg(in);
- ident = lowercase(p.read_all_as_string());
+ ident = lowercase_facet(p.read_all_as_string());
}
@@ -118,19 +115,19 @@ sqlite_sha1_fn(sqlite3_context *f, int n
if (nargs == 1)
{
- string s = (sqlite3_value_text_s(args[0]));
+ string s = reinterpret_cast<char const*>(sqlite3_value_text(args[0]));
s.erase(remove_if(s.begin(), s.end(), is_ws()),s.end());
tmp = s;
}
else
{
- string sep = string(sqlite3_value_text_s(args[0]));
- string s = (sqlite3_value_text_s(args[1]));
+ string sep = string(reinterpret_cast<char const*>(sqlite3_value_text(args[0])));
+ string s = reinterpret_cast<char const*>(sqlite3_value_text(args[1]));
s.erase(remove_if(s.begin(), s.end(), is_ws()),s.end());
tmp = s;
for (int i = 2; i < nargs; ++i)
{
- s = string(sqlite3_value_text_s(args[i]));
+ s = string(reinterpret_cast<char const*>(sqlite3_value_text(args[i])));
s.erase(remove_if(s.begin(), s.end(), is_ws()),s.end());
tmp += sep + s;
}
@@ -908,6 +905,135 @@ migrate_client_to_add_rosters(sqlite3 *
return true;
}
+static void
+sqlite3_unbase64_fn(sqlite3_context *f, int nargs, sqlite3_value ** args)
+{
+ if (nargs != 1)
+ {
+ sqlite3_result_error(f, "need exactly 1 arg to unbase64()", -1);
+ return;
+ }
+ data decoded;
+ decode_base64(base64<data>(string(reinterpret_cast<char const*>(sqlite3_value_text(args[0])))), decoded);
+ sqlite3_result_blob(f, decoded().c_str(), decoded().size(), SQLITE_TRANSIENT);
+}
+
+// I wish I had a form of ALTER TABLE COMMENT on sqlite3
+static bool
+migrate_files_BLOB(sqlite3 * sql,
+ char ** errmsg,
+ app_state *app)
+{
+ int res;
+ I(sqlite3_create_function(sql, "unbase64", -1,
+ SQLITE_UTF8, NULL,
+ &sqlite3_unbase64_fn,
+ NULL, NULL) == 0);
+ // change the encoding of file(_delta)s
+ if (!move_table(sql, errmsg,
+ "files",
+ "tmp",
+ "("
+ "id primary key,"
+ "data not null"
+ ")"))
+ return false;
+
+ res = logged_sqlite3_exec(sql, "CREATE TABLE files\n"
+ "\t(\n"
+ "\tid primary key, -- strong hash of file contents\n"
+ "\tdata not null -- compressed contents of a file\n"
+ "\t)", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+
+ res = logged_sqlite3_exec(sql, "INSERT INTO files "
+ "SELECT id, unbase64(data) "
+ "FROM tmp", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+
+ res = logged_sqlite3_exec(sql, "DROP TABLE tmp", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+
+ if (!move_table(sql, errmsg,
+ "file_deltas",
+ "tmp",
+ "("
+ "id not null,"
+ "base not null,"
+ "delta not null"
+ ")"))
+ return false;
+
+ res = logged_sqlite3_exec(sql, "CREATE TABLE file_deltas\n"
+ "\t(\n"
+ "\tid not null, -- strong hash of file contents\n"
+ "\tbase not null, -- joins with files.id or file_deltas.id\n"
+ "\tdelta not null, -- compressed rdiff to construct current from base\n"
+ "\tunique(id, base)\n"
+ "\t)", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+
+ res = logged_sqlite3_exec(sql, "INSERT INTO file_deltas "
+ "SELECT id, base, unbase64(delta) "
+ "FROM tmp", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+
+ res = logged_sqlite3_exec(sql, "DROP TABLE tmp", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+
+ // migrate other contents which are accessed by get|put_version
+ res = logged_sqlite3_exec(sql, "UPDATE manifests SET data=unbase64(data)",
+ NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ res = logged_sqlite3_exec(sql, "UPDATE manifest_deltas "
+ "SET delta=unbase64(delta)", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ res = logged_sqlite3_exec(sql, "UPDATE rosters SET data=unbase64(data) ",
+ NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ res = logged_sqlite3_exec(sql, "UPDATE roster_deltas "
+ "SET delta=unbase64(delta)", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+
+ res = logged_sqlite3_exec(sql, "UPDATE db_vars "
+ "SET value=unbase64(value),name=unbase64(name)", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ res = logged_sqlite3_exec(sql, "UPDATE public_keys "
+ "SET keydata=unbase64(keydata)", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ res = logged_sqlite3_exec(sql, "UPDATE revision_certs "
+ "SET value=unbase64(value),signature=unbase64(signature)",
+ NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ res = logged_sqlite3_exec(sql, "UPDATE manifest_certs "
+ "SET value=unbase64(value),signature=unbase64(signature) ",
+ NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ res = logged_sqlite3_exec(sql, "UPDATE revisions "
+ "SET data=unbase64(data)", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ res = logged_sqlite3_exec(sql, "UPDATE branch_epochs "
+ "SET branch=unbase64(branch)", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ return true;
+}
+
void
migrate_monotone_schema(sqlite3 *sql, app_state *app)
{
@@ -939,6 +1065,9 @@ migrate_monotone_schema(sqlite3 *sql, ap
m.add("bd86f9a90b5d552f0be1fa9aee847ea0f317778b",
&migrate_client_to_add_rosters);
+ m.add("1db80c7cee8fa966913db1a463ed50bf1b0e5b0e",
+ &migrate_files_BLOB);
+
// IMPORTANT: whenever you modify this to add a new schema version, you must
// also add a new migration test for the new schema version. See
// tests/t_migrate_schema.at for details.
============================================================
--- std_hooks.lua 87a925a89f17ae312390049e28296bbb9f7ee170
+++ std_hooks.lua 4ca1188ac09063710baa429986649f2c3ad13083
@@ -70,6 +70,15 @@ attr_functions["mtn:execute"] =
end
end
+function dir_matches(name, dir)
+ -- helper for ignore_file, matching files within dir, or dir itself.
+ -- eg for dir of 'CVS', matches CVS/, CVS/*, */CVS/ and */CVS/*
+ if (string.find(name, "^" .. dir .. "/")) then return true end
+ if (string.find(name, "^" .. dir .. "$")) then return true end
+ if (string.find(name, "/" .. dir .. "/")) then return true end
+ if (string.find(name, "/" .. dir .. "$")) then return true end
+ return false
+end
function ignore_file(name)
-- project specific
@@ -124,26 +133,21 @@ function ignore_file(name)
-- emacs creates #foo# files
if (string.find(name, "%#[^/]*%#$")) then return true end
-- autotools detritus:
- if (string.find(name, "^autom4te.cache/")) then return true end
- if (string.find(name, "/autom4te.cache/")) then return true end
- if (string.find(name, "^.deps/")) then return true end
- if (string.find(name, "/.deps/")) then return true end
+ if dir_matches(name, "autom4te.cache") then return true end
+ if dir_matches(name, ".deps") then return true end
-- Cons/SCons detritus:
- if (string.find(name, "^.consign$")) then return true end
- if (string.find(name, "/.consign$")) then return true end
- if (string.find(name, "^.sconsign$")) then return true end
- if (string.find(name, "/.sconsign$")) then return true end
+ if dir_matches(name, ".consign") then return true end
+ if dir_matches(name, ".sconsign") then return true end
-- other VCSes:
- if (string.find(name, "^CVS/")) then return true end
- if (string.find(name, "/CVS/")) then return true end
- if (string.find(name, "^%.svn/")) then return true end
- if (string.find(name, "/%.svn/")) then return true end
- if (string.find(name, "^SCCS/")) then return true end
- if (string.find(name, "/SCCS/")) then return true end
- if (string.find(name, "^_darcs/")) then return true end
- if (string.find(name, "^.cdv/")) then return true end
- if (string.find(name, "^.git/")) then return true end
- if (string.find(name, "%.scc$")) then return true end
+ if dir_matches(name, "CVS") then return true end
+ if dir_matches(name, ".svn") then return true end
+ if dir_matches(name, "SCCS") then return true end
+ if dir_matches(name, "_darcs") then return true end
+ if dir_matches(name, ".cdv") then return true end
+ if dir_matches(name, ".git") then return true end
+ if dir_matches(name, ".scc") then return true end
+ if dir_matches(name, ".bzr") then return true end
+ if dir_matches(name, ".hg") then return true end
-- desktop/directory configuration metadata
if (string.find(name, "^.DS_Store$")) then return true end
if (string.find(name, "/.DS_Store$")) then return true end
============================================================
--- tests/t_log_nofiles_merges.at 958b5e4229b1afd2c7ec131d0a239b28d792815f
+++ tests/t_log_nofiles_nomerges.at dedc7b333ac5e779f29464a1f62285ec787b6dd4
@@ -30,12 +30,12 @@ R2=`BASE_REVISION`
AT_CHECK(MONOTONE update, [], [ignore], [ignore])
R2=`BASE_REVISION`
-# check that merge is excluded from log output
+# check that merge is included by default
AT_CHECK(MONOTONE log, [], [stdout], [ignore])
-AT_CHECK(grep '^Revision' stdout | grep $R2, [1], [ignore])
+AT_CHECK(grep '^Revision' stdout | grep $R2, [], [ignore])
-# and that it has been included by --merges
-AT_CHECK(MONOTONE log --merges, [], [stdout], [ignore])
-AT_CHECK(grep '^Revision' stdout | grep $R2, [], [ignore])
+# and that it is excluded by --no-merges
+AT_CHECK(MONOTONE log --no-merges, [], [stdout], [ignore])
+AT_CHECK(grep '^Revision' stdout | grep $R2, [1], [ignore])
AT_CLEANUP
============================================================
--- tests/t_migrate_schema.at 9d9a73cc20f8e367f4c828484e78c19224614b93
+++ tests/t_migrate_schema.at e5b24dd9ccc44e36b20d1b1dc89509f0e99896fd
@@ -284,4 +284,181 @@ 5Zv/XbuXQ1m/fTpA9kr7T0e2Pv780pGhadLlP3b/
5Zv/XbuXQ1m/fTpA9kr7T0e2Pv780pGhadLlP3b/B/9helPJSAAA
])
+CHECK_MIGRATE_FROM([9d2b5d7b86df00c30ac34fe87a3c20f1195bb2df],
+[H4sIANfQ6UMCA+2cW2+dR5aer61fQfSNbEDt1Pkwc9OeiZEY6HEDbc+ggSAQ6tjiRCYVkupp
+//s870dLoiTS3pQyyE2sbomHvb86rfUeqlbtf/r2v333/dm3f/nnP/7rD9/927f/+OSf//zt
+Nz9+e/bjN//0x2/P+lW7GC+er1eX48X1ky++fPLFi3b94uzi8ubs4vXLl2evL87/9+v17OzN
+f7///dnxgst9drV+aucX5xd/Pdvn6+W8Prter9pVu1nzrP989rt/+N2TL26f/tDTeNa/X55f
+XJ/9x/nNCx73t/Pr88uL52Nd3Vx//bf28vV68sXRsXcP+OA/nkAL8/Knsxfr779fF+Ny0vr5
+fPLFVx+Mc/bnf2tX10/evPPLt1/xbobxtolnb598PS5fLQ20vXr18ny0Gzp3fHvGk96+/aL9
+tD588/F2XnT2v9bPb194DOijV/7ywtvRvnnp7TR9eduzZ0cTX7395Ycj2+cv1/O5Xt602/U7
+n/eN5ebqkoV6s3R6z9m4vLhZFze8q7frD3r2/tLo5ddf8+DLq7vNfa2JPr587828d1z+9Opq
+XV+zGFfzfO+zm0s1Ry9ej5uz8frqiobP9hULp7affPHLiM/ns+MHXx0L+N33P3z75x/Pvvv+
+xz/dbfbs3775479++8OXT1sdLRubam6zLZNSr2ma3Frv3mwzkwsxVTeePns6Q3V1u5Cm8y3a
+1VvKtaYSlyu7tm5y7qH49vTZX57aXbop5s5/e28fgzcrhua9G96vsJxxxqw2SnOxmnb7yqcn
+dNunXV0JZo69m3Mmhe7mrMuUUKYNPtL3PKK6veuMtrSwrDdl9FWi8X3OsmMu3aa5QjA5VHtS
+t9u7bvvW+deux3TbVPo3QvK2OdOGTcmHsCPD93stE1oaKaQW6LZdYyXD9Nbda0huLhezTdaa
+nGpv07ZiVpnlpG7Xd92uLeTgqr3b7Y9y4W0WvLo6/6ld/awkfHZKFsx2J5DfJM6dSH7zylsM
+0JvvjdJ3M/a5QRf6L8F2DJ6Z9ExsNPHhNXvXdu+rzV0WM+nKqCt6npPtaNvFEm2oxZu0evrV
+tpemXm1vO+knwXZS258btUfb7c24Y16j9ZlPa/tzQ+9ou75pu4Akw2x3t+33Au6ndnG+1/XN
+LWn9Kn8+jjk/RvH7OPNN82/A+W137gD0/QR1POnyVaNzSgv1Zby4vF4X6sHr63X15Iv7Cevu
+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
+D6TSUF9iWAAA
+])
+
AT_CLEANUP
============================================================
--- tests/t_sql_unpack.at 1bb994c7c10fcfafc2a0fc9b5dd7c45b5b315174
+++ tests/t_sql_gunzip.at 1e43988cec90fe9e16a51379b7b832cfc609d122
@@ -1,13 +1,9 @@
-AT_SETUP([sql functions unpack, unbase64])
+AT_SETUP([sql function gunzip (which replaced unpack)])
MONOTONE_SETUP
-AT_CHECK(MONOTONE db execute "select unpack('H4sIAAAAAAAAAE2RQW4bMQwA7/uKRe5JJEoUyXOu/YFhGJREJgvEq8BetOjvq/bg9EyQMxju9uty1X1zux/riQSbM2lsiZxSzI6qhSVayh0KKSF51XJelvHZLzf7ud23sa8n65KtJSfOkUTcQyRVLMFRIPfgSt4C9vO/vW8gGJVMjiFxCIEqd0rgbowhZ6AOoQAUlQn80qN9rE8v1+NZj+N2f1pWv43rlK6F0MQ6ilnrUnWKZHMGjlLaPCEdVdJ5Wdf1GOvJpRbs4hGpWiVJUCFYVkabg8wkWbTbf9C3D93f7cd4f0Ch6kySCnTiktRQggALCSXClr2TYYnAD2ggDIXD1IyhUmIs3jqyxb9dHG3G6jXH/A1tYz9uW31tm9ZxXK5jH8fY7eXr98NiLnNjT1VxhgR2lQoxSw05okaKyQtJxIcFJ20cerbSySMDzq+CZbKoSVKtmDqgVjgvfwA6AWjaGQIAAA==')", [], [stdout], [ignore])
+AT_CHECK(MONOTONE db execute "select gunzip(X'1f8b08000000000000004d91416e1b310c00effb8a45ee49244a14c973aefd8161189444260bc4abc05eb4e8efabf6e0f44c903318eef6eb72d57d73bb1feb89049b33696c899c52cc8eaa85255aca1d0a292179d5725e96f1d92f37fbb9ddb7b1af27eb92ad2527ce9144dc4324552cc15120f7e04ade02f6f3bfbd6f2018954c8e217108812a774ae06e8c2167a00ea100149509fcd2a37dac4f2fd7e3598fe3767f5a56bf8deb94ae85d0c43a8a59eb52758a6473068e52da3c211d55d27959d7f518ebc9a516ece211a95a254950215856469b83cc2459b4db7fd0b70fdddfedc7787f40a1ea4c920a74e292d45082000b0925c296bd936189c00f68200c85c3d48ca152622cde3ab2c5bf5d1c6dc6ea35c7fc0d6d633f6e5b7d6d9bd6715cae631fc7d8ede5ebf7c3622e73634f5571860476950a314b0d39a2468ac90b49c48705276d1c7ab6d2c92303ceaf8265b2a84952ad983aa056382f7f003a0168da19020000')", [], [stdout], [ignore])
AT_CHECK(QGREP('new_manifest \@<:@795cf87a1c37f7314f5aa6891e34d267a757fba6\@:>@' stdout))
AT_CHECK(QGREP('from \@<:@7b675e9ed59eecd9bac3f4ef828196c2069d5a93\@:>@' stdout))
-AT_CHECK(MONOTONE db execute "select unbase64('aXQncyB0ZW4gcGFjZXMgbm9ydGh3ZXN0IG9mIHRoZSBwYWxtIHRyZWUuICBGT09CQVI=')", [], [stdout], [ignore])
-
-AT_CHECK(QGREP(FOOBAR stdout))
-
AT_CLEANUP
============================================================
--- testsuite.at c8be08d87b48f90c833c326e708aaa06423b1b75
+++ testsuite.at d67ef3223629641b02551a0a31cbf4644cd60d82
@@ -639,7 +639,7 @@ m4_include(tests/t_db_execute.at)
m4_include(tests/t_commit_log_3.at)
m4_include(tests/t_at_sign.at)
m4_include(tests/t_db_execute.at)
-m4_include(tests/t_sql_unpack.at)
+m4_include(tests/t_sql_gunzip.at)
m4_include(tests/t_final_space.at)
m4_include(tests/t_inodeprints.at)
m4_include(tests/t_inodeprints_update.at)
@@ -776,6 +776,11 @@ m4_include(tests/t_db_kill_rev_locally_2
m4_include(tests/t_ls_changed.at)
m4_include(tests/t_revert_new_project.at)
m4_include(tests/t_db_kill_rev_locally_2.at)
-m4_include(tests/t_log_nofiles_merges.at)
+m4_include(tests/t_log_nofiles_nomerges.at)
m4_include(tests/t_cvsimport_branch.at)
m4_include(tests/t_log_to_file.at)
+m4_include(tests/t_log_selectors.at)
+m4_include(tests/t_pivot_root.at)
+m4_include(tests/t_pivot_root_revert.at)
+m4_include(tests/t_pivot_root_update.at)
+m4_include(tests/t_rosterify_root_suture.at)
============================================================
--- work.cc 39e5c9ecd7f5209dbcbb7e631d6fc044296a4a67
+++ work.cc be9eb83e519a1395626b2b29868af63e46a958c2
@@ -28,7 +28,7 @@ string const attr_file_name(".mt-attrs")
string const attr_file_name(".mt-attrs");
-void
+void
file_itemizer::visit_dir(file_path const & path)
{
this->visit_file(path);
@@ -347,7 +347,70 @@ perform_rename(set<file_path> const & sr
update_any_attrs(app);
}
+void
+perform_pivot_root(file_path const & new_root, file_path const & put_old,
+ app_state & app)
+{
+ split_path new_root_sp, put_old_sp, root_sp;
+ new_root.split(new_root_sp);
+ put_old.split(put_old_sp);
+ file_path().split(root_sp);
+ temp_node_id_source nis;
+ roster_t base_roster, new_roster;
+ get_base_and_current_roster_shape(base_roster, new_roster, nis, app);
+
+ I(new_roster.has_root());
+ N(new_roster.has_node(new_root_sp),
+ F("proposed new root directory '%s' is not versioned or does not exist") % new_root);
+ N(is_dir_t(new_roster.get_node(new_root_sp)),
+ F("proposed new root directory '%s' is not a directory") % new_root);
+ {
+ split_path new_root_MT;
+ (new_root / bookkeeping_root.as_internal()).split(new_root_MT);
+ N(!new_roster.has_node(new_root_MT),
+ F("proposed new root directory '%s' contains illegal path %s") % new_root % bookkeeping_root);
+ }
+
+ {
+ file_path current_path_to_put_old = (new_root / put_old.as_internal());
+ split_path current_path_to_put_old_sp, current_path_to_put_old_parent_sp;
+ path_component basename;
+ current_path_to_put_old.split(current_path_to_put_old_sp);
+ dirname_basename(current_path_to_put_old_sp, current_path_to_put_old_parent_sp, basename);
+ N(new_roster.has_node(current_path_to_put_old_parent_sp),
+ F("directory '%s' is not versioned or does not exist")
+ % file_path(current_path_to_put_old_parent_sp));
+ N(is_dir_t(new_roster.get_node(current_path_to_put_old_parent_sp)),
+ F("'%s' is not a directory")
+ % file_path(current_path_to_put_old_parent_sp));
+ N(!new_roster.has_node(current_path_to_put_old_sp),
+ F("'%s' is in the way") % current_path_to_put_old);
+ }
+
+ cset cs;
+ safe_insert(cs.nodes_renamed, std::make_pair(root_sp, put_old_sp));
+ safe_insert(cs.nodes_renamed, std::make_pair(new_root_sp, root_sp));
+
+ {
+ editable_roster_base e(new_roster, nis);
+ cs.apply_to(e);
+ }
+ {
+ cset new_work;
+ make_cset(base_roster, new_roster, new_work);
+ put_work_cset(new_work);
+ }
+ if (app.execute)
+ {
+ empty_file_content_source efcs;
+ editable_working_tree e(app, efcs);
+ cs.apply_to(e);
+ }
+ update_any_attrs(app);
+}
+
+
// work file containing rearrangement from uncommitted adds/drops/renames
std::string const work_file_name("work");
@@ -599,7 +662,7 @@ read_options_map(data const & dat, optio
parser.sym(opt);
parser.str(val);
// options[opt] = val;
- // use non-replacing insert verses replacing with options[opt] = val;
+ // use non-replacing insert versus replacing with options[opt] = val;
options.insert(make_pair(opt, val));
}
}
@@ -732,34 +795,58 @@ editable_working_tree::editable_working_
editable_working_tree::editable_working_tree(app_state & app,
file_content_source const & source)
- : app(app), source(source), next_nid(1)
+ : app(app), source(source), next_nid(1), root_dir_attached(true)
{
}
-void
-move_path_if_not_already_present(any_path const & old_path,
- any_path const & new_path,
- app_state & app)
-{
-}
-
static inline bookkeeping_path
path_for_nid(node_id nid)
{
return bookkeeping_root / "tmp" / boost::lexical_cast<std::string>(nid);
}
+// Attaching/detaching the root directory:
+// This is tricky, because we don't want to simply move it around, like
+// other directories. That would require some very snazzy handling of the
+// MT directory, and never be possible on windows anyway[1]. So, what we do
+// is fake it -- whenever we want to move the root directory into the
+// temporary dir, we instead create a new dir in the temporary dir, move
+// all of the root's contents into this new dir, and make a note that the root
+// directory is logically non-existent. Whenever we want to move some
+// directory out of the temporary dir and onto the root directory, we instead
+// check that the root is logically nonexistent, move its contents, and note
+// that it exists again.
+//
+// [1] Because the root directory is our working directory, and thus locked in
+// place. We _could_ chdir out, then move MT out, then move the real root
+// directory into our newly-moved MT, etc., but aside from being very finicky,
+// this would require that we know our root directory's name relative to its
+// parent.
+
node_id
editable_working_tree::detach_node(split_path const & src)
{
+ I(root_dir_attached);
node_id nid = next_nid++;
file_path src_pth(src);
- // can't detach the root dir
- E(!(src_pth == file_path()), F("cannot delete or rename the root directory"));
bookkeeping_path dst_pth = path_for_nid(nid);
safe_insert(rename_add_drop_map, make_pair(dst_pth, src_pth));
make_dir_for(dst_pth);
- move_path(src_pth, dst_pth);
+ if (src_pth == file_path())
+ {
+ // root dir detach, so we move contents, rather than the dir itself
+ mkdir_p(dst_pth);
+ std::vector<utf8> files, dirs;
+ read_directory(src_pth, files, dirs);
+ for (std::vector<utf8>::const_iterator i = files.begin(); i != files.end(); ++i)
+ move_file(src_pth / (*i)(), dst_pth / (*i)());
+ for (std::vector<utf8>::const_iterator i = dirs.begin(); i != dirs.end(); ++i)
+ if (!bookkeeping_path::is_bookkeeping_path((*i)()))
+ move_dir(src_pth / (*i)(), dst_pth / (*i)());
+ root_dir_attached = false;
+ }
+ else
+ move_path(src_pth, dst_pth);
return nid;
}
@@ -807,20 +894,14 @@ editable_working_tree::attach_node(node_
// Possibly just write data out into the workspace, if we're doing
// a file-create (not a dir-create or file/dir rename).
- if (!file_exists(src_pth))
+ if (!path_exists(src_pth))
{
+ I(root_dir_attached);
std::map<bookkeeping_path, file_id>::const_iterator i
= written_content.find(src_pth);
if (i != written_content.end())
{
- if (file_exists(dst_pth))
- {
- file_id dst_id;
- ident_existing_file(dst_pth, dst_id, app.lua);
- if (i->second == dst_id)
- return;
- }
- P(F("adding %s") % dst_pth);
+ P(F("adding '%s'") % dst_pth);
file_data dat;
source.get_file_content(i->second, dat);
write_localized_data(dst_pth, dat.inner(), app.lua);
@@ -828,33 +909,47 @@ editable_working_tree::attach_node(node_
}
}
+ // FIXME: it is weird to do this here, instead of up above, but if we do it
+ // up above a lot of tests break. those tests are arguably broken -- they
+ // depend on 'update' clobbering existing, non-versioned files -- but
+ // putting this up there doesn't actually help, since if we abort in the
+ // middle of an update to avoid clobbering a file, we just end up leaving
+ // the working copy in an inconsistent state instead. so for now, we leave
+ // this check down here.
+ require_path_