You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1200 lines
43 KiB

This is the RSE patchset for the Monotone VCS.
The patchset is entirely enclosed in...
#if defined(RSE) /* <tag> */
[...]
#endif
...and this way can be clearly distinguished. The <tag> corresponds
the following major changes it includes:
o environment-variables:
This adds the two environment variables MTN_DBFILE and MTN_KEYDIR as
defaults for the (bootstrapping) mtn(1) command line options --db
and --keydir. This allows you to provide values for them without
having to pass the options all the time.
o alt-book-keeping-root:
This allows mtn(1) to accept an alternative book-keeping directory.
The default still is "_MTN", but alternatively one can rename this
to ".mtn". If one sets the environment variable "MTN_BKROOT" one can
change ".mtn" to an arbitrary sub-directory name and additionally
even force its use on workspace creation operations.
o cosmetics-netsync:
This is just a small cosmetics change. It reduces the annoying
"doing anonymous pull; use -kKEYNAME if you need authentication" to
just "doing anonymous pull" as mtn(1) doesn't have to teach people.
That's for what the documentation is for.
o cosmetics-stat:
The workspace top-level directory is shown as "" instead of nothing.
o cosmetics-diff-and-log:
This cosmetically "improves" the output of "mtn diff" and "mtn
log". For "mtn diff" The output of "mtn diff" now uses a separator
line consisting of 67 (instead of 60) "=" characters to align
with cvs(1)'s well known output. Additionally, two new command
line options for "mtn diff" allow one to disable some outputs:
"--no-show-header" disables the output of the redundant "#..."
header lines at the top of the output and "--no-show-separator"
disables the output of the separator line at all. The output of "mtn
log" is improved by aligning the single-line certificate values and
by indenting the file change information by just 4 instead of 8
characters.
o diff-index:
This adds "Index:" lines to the output of "mtn diff" in order to
align with the "svn diff" and "cvs diff" outputs. This also helps
patch(1) to clearly identify the file to patch.
o extra-commands:
This adds "mtn fuse", "mtn conflicts", "mtn revision" and "mtn base"
commands. They are all simple but convenient Lua wrappers.
o dot-mtn-message:
Support a ".mtn-message" file in the root-directory as a template
for the commit messages.
o lua-rel-path:
Support for additional Lua function workspace_relpath() for
receiving the "initial relative path" within the workspace (which
is important to know because in a Lua hook the current working
directory was changed to the workspace root).
Ralf S. Engelschall
rse@engelschall.com
www.engelschall.com
===================================================================
Index: cmd_diff_log.cc
--- cmd_diff_log.cc 37b1cfffa001ccc5b813fe6f0e84dc6a5dc3996e
+++ cmd_diff_log.cc 4d6a26b3146f903df899a4777f8f556c7e5704e4
@@ -99,6 +99,27 @@ print_indented_set(ostream & os,
set<file_path> const & s,
size_t max_cols)
{
+#if defined(RSE) /* cosmetics-diff-and-log */
+ size_t cols = 4;
+ os << " ";
+ for (set<file_path>::const_iterator i = s.begin();
+ i != s.end(); i++)
+ {
+ const string str = lexical_cast<string>(*i);
+ if (cols > 4 && cols + str.size() + 1 >= max_cols)
+ {
+ cols = 4;
+ os << "\n ";
+ }
+ else if (cols > 4) {
+ os << ' ';
+ cols += 1;
+ }
+ os << str;
+ cols += str.size();
+ }
+ os << '\n';
+#else
size_t cols = 8;
os << " ";
for (set<file_path>::const_iterator i = s.begin();
@@ -116,6 +137,7 @@ print_indented_set(ostream & os,
cols += str.size() + 1;
}
os << '\n';
+#endif
}
void
@@ -134,7 +156,11 @@ changes_summary::print(ostream & os, siz
for (map<file_path, file_path>::const_iterator
i = cs.nodes_renamed.begin();
i != cs.nodes_renamed.end(); i++)
+#if defined(RSE) /* cosmetics-diff-and-log */
+ os << " " << i->first
+#else
os << " " << i->first
+#endif
<< " to " << i->second << '\n';
}
@@ -229,7 +255,12 @@ static void
}
static void
+#if defined(RSE) /* cosmetics-diff-and-log */
+dump_diffs(app_state & app,
+ lua_hooks & lua,
+#else
dump_diffs(lua_hooks & lua,
+#endif
database & db,
cset const & cs,
set<file_path> const & paths,
@@ -240,8 +271,13 @@ dump_diffs(lua_hooks & lua,
bool show_encloser,
bool limit_paths)
{
+#if defined(RSE) /* cosmetics-diff-and-log */
+ // 67 is somewhat arbitrary (CVS uses this), but less than 80
+ string patch_sep = string(67, '=');
+#else
// 60 is somewhat arbitrary, but less than 80
string patch_sep = string(60, '=');
+#endif
for (map<file_path, file_id>::const_iterator
i = cs.files_added.begin();
@@ -250,6 +286,9 @@ dump_diffs(lua_hooks & lua,
if (limit_paths && paths.find(i->first) == paths.end())
continue;
+#if defined(RSE) /* cosmetics-diff-and-log */
+ if (!app.opts.no_show_separator)
+#endif
output << patch_sep << '\n';
data unpacked;
vector<string> lines;
@@ -296,6 +335,9 @@ dump_diffs(lua_hooks & lua,
file_data f_old;
data data_old, data_new;
+#if defined(RSE) /* cosmetics-diff-and-log */
+ if (!app.opts.no_show_separator)
+#endif
output << patch_sep << '\n';
if (old_is_archived)
@@ -342,7 +384,12 @@ static void
}
static void
+#if defined(RSE) /* cosmetics-diff-and-log */
+dump_diffs(app_state & app,
+ lua_hooks & lua,
+#else
dump_diffs(lua_hooks & lua,
+#endif
database & db,
cset const & cs,
std::ostream & output,
@@ -352,8 +399,13 @@ dump_diffs(lua_hooks & lua,
bool show_encloser)
{
set<file_path> dummy;
+#if defined(RSE) /* cosmetics-diff-and-log */
+ dump_diffs(app, lua, db, cs, dummy, output,
+ diff_format, new_is_archived, old_is_archived, show_encloser, false);
+#else
dump_diffs(lua, db, cs, dummy, output,
diff_format, new_is_archived, old_is_archived, show_encloser, false);
+#endif
}
// common functionality for diff and automate content_diff to determine
@@ -569,9 +621,15 @@ CMD(diff, "diff", "di", CMD_REF(informat
}
else
{
+#if defined(RSE) /* cosmetics-diff-and-log */
+ dump_diffs(app, app.lua, db, included, cout,
+ app.opts.diff_format, new_is_archived, old_is_archived,
+ !app.opts.no_show_encloser);
+#else
dump_diffs(app.lua, db, included, cout,
app.opts.diff_format, new_is_archived, old_is_archived,
!app.opts.no_show_encloser);
+#endif
}
}
@@ -606,8 +664,13 @@ CMD_AUTOMATE(content_diff, N_("[FILE [..
dump_header(dummy_header, included, output, false);
}
+#if defined(RSE) /* cosmetics-diff-and-log */
+ dump_diffs(app, app.lua, db, included, output,
+ app.opts.diff_format, new_is_archived, old_is_archived, !app.opts.no_show_encloser);
+#else
dump_diffs(app.lua, db, included, output,
app.opts.diff_format, new_is_archived, old_is_archived, !app.opts.no_show_encloser);
+#endif
}
@@ -1048,7 +1111,11 @@ CMD(log, "log", "", CMD_REF(informative)
else
{
out << string(65, '-') << '\n';
+#if defined(RSE) /* cosmetics-diff-and-log */
+ out << _("Revision: ") << rid << '\n';
+#else
out << _("Revision: ") << rid << '\n';
+#endif
changes_summary csum;
@@ -1063,12 +1130,23 @@ CMD(log, "log", "", CMD_REF(informative)
for (set<revision_id>::const_iterator anc = ancestors.begin();
anc != ancestors.end(); ++anc)
+#if defined(RSE) /* cosmetics-diff-and-log */
+ out << _("Ancestor: ") << *anc << '\n';
+#else
out << _("Ancestor: ") << *anc << '\n';
+#endif
+#if defined(RSE) /* cosmetics-diff-and-log */
+ log_certs(certs, out, author_name, _("Author: "), false);
+ log_date_certs(certs, out, date_fmt, _("Date: "), false);
+ log_certs(certs, out, branch_name, _("Branch: "), false);
+ log_certs(certs, out, tag_name, _("Tag: "), false);
+#else
log_certs(certs, out, author_name, _("Author: "), false);
log_date_certs(certs, out, date_fmt, _("Date: "), false);
log_certs(certs, out, branch_name, _("Branch: "), false);
log_certs(certs, out, tag_name, _("Tag: "), false);
+#endif
if (!app.opts.no_files && !csum.cs.empty())
{
@@ -1078,16 +1156,26 @@ CMD(log, "log", "", CMD_REF(informative)
}
log_certs(certs, out, changelog_name, _("ChangeLog: "), true);
+#if defined(RSE) /* cosmetics-diff-and-log */
+ log_certs(certs, out, comment_name, _("Comments: "), true);
+#else
log_certs(certs, out, comment_name, _("Comments: "), true);
+#endif
}
if (app.opts.diffs)
{
for (edge_map::const_iterator e = rev.edges.begin();
e != rev.edges.end(); ++e)
+#if defined(RSE) /* cosmetics-diff-and-log */
+ dump_diffs(app, app.lua, db, edge_changes(e), diff_paths, out,
+ app.opts.diff_format, true, true,
+ !app.opts.no_show_encloser, !mask.empty());
+#else
dump_diffs(app.lua, db, edge_changes(e), diff_paths, out,
app.opts.diff_format, true, true,
!app.opts.no_show_encloser, !mask.empty());
+#endif
}
if (next > 0)
===================================================================
Index: cmd_netsync.cc
--- cmd_netsync.cc e70435eb00dcd606984f40ca8b4a53996985fc72
+++ cmd_netsync.cc 182df7fa258a5858106a8eb038fe4f84083e813b
@@ -519,7 +519,11 @@ CMD(pull, "pull", "", CMD_REF(network),
args, info, false);
if (!keys.have_signing_key())
+#if defined(RSE) /* cosmetics-netsync */
+ P(F("doing anonymous pull"));
+#else
P(F("doing anonymous pull; use -kKEYNAME if you need authentication"));
+#endif
run_netsync_protocol(app, app.opts, app.lua, project, keys,
client_voice, sink_role, info);
@@ -698,9 +702,16 @@ CMD(clone, "clone", "", CMD_REF(network)
// paths.cc's idea of the current workspace root is wrong at this point
if (internal_db)
+#if defined(RSE) /* alt-book-keeping-root */
+ app.opts.dbname = system_path((directory_exists(workspace_dir / alt_bookkeeping_root_component) ?
+ (workspace_dir / alt_bookkeeping_root_component) :
+ (workspace_dir / bookkeeping_root_component))
+ / ws_internal_db_file_name);
+#else
app.opts.dbname = system_path(workspace_dir
/ bookkeeping_root_component
/ ws_internal_db_file_name);
+#endif
// this is actually stupid, but app.opts.branch must be set here
// otherwise it will not be written into _MTN/options, in case
@@ -725,7 +736,11 @@ CMD(clone, "clone", "", CMD_REF(network)
info, true, true, false);
if (!keys.have_signing_key())
+#if defined(RSE) /* cosmetics-netsync */
+ P(F("doing anonymous pull"));
+#else
P(F("doing anonymous pull; use -kKEYNAME if you need authentication"));
+#endif
// make sure we're back in the original dir so that file: URIs work
change_current_working_dir(start_dir);
===================================================================
Index: cmd_ws_commit.cc
--- cmd_ws_commit.cc 8f12395a73d4c2fbd19e4eac883b719e581d0ae7
+++ cmd_ws_commit.cc 490bc6a101d7de1b85203d5c3a135fafbbff59a4
@@ -94,7 +94,14 @@ revision_summary(revision_t const & rev,
for (set<file_path>::const_iterator i = cs.dirs_added.begin();
i != cs.dirs_added.end(); ++i)
+#if defined(RSE) /* cosmetics-stat */
+ if ((*i) == file_path())
+ out += (F(" added \"\"")).str() += '\n';
+ else
+ out += (F(" added %s") % *i).str() += '\n';
+#else
out += (F(" added %s") % *i).str() += '\n';
+#endif
for (map<file_path, file_id>::const_iterator i = cs.files_added.begin();
i != cs.files_added.end(); ++i)
@@ -1493,12 +1500,20 @@ CMD_NO_WORKSPACE(import, "import", "", C
catch (...)
{
// clean up before rethrowing
+#if defined(RSE) /* alt-book-keeping-root */
+ delete_dir_recursive(directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root);
+#else
delete_dir_recursive(bookkeeping_root);
+#endif
throw;
}
// clean up
+#if defined(RSE) /* alt-book-keeping-root */
+ delete_dir_recursive(directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root);
+#else
delete_dir_recursive(bookkeeping_root);
+#endif
}
CMD_NO_WORKSPACE(migrate_workspace, "migrate_workspace", "", CMD_REF(tree),
===================================================================
Index: diff_output.cc
--- diff_output.cc 746af1eeaa7fee943bf1264dc88ddd6e218c7866
+++ diff_output.cc a2e01d5f3517b7393711c3bfca7e7eb5a8b9772b
@@ -566,6 +566,9 @@ make_diff(string const & filename1,
{
case unified_diff:
{
+#if defined(RSE) /* diff-index */
+ ost << "Index: " << filename2 << '\n';
+#endif
ost << "--- " << filename1 << '\t'
<< id1 << '\n';
ost << "+++ " << filename2 << '\t'
@@ -577,6 +580,9 @@ make_diff(string const & filename1,
}
case context_diff:
{
+#if defined(RSE) /* diff-index */
+ ost << "Index: " << filename2 << '\n';
+#endif
ost << "*** " << filename1 << '\t'
<< id1 << '\n';
ost << "--- " << filename2 << '\t'
===================================================================
Index: file_io.cc
--- file_io.cc 6683cf8d459a89597caf1eb3ce01800fe4404643
+++ file_io.cc 4faf0094870242fac6a9d1543e2239448453f407
@@ -342,16 +342,36 @@ write_data(file_path const & path, data
write_data(file_path const & path, data const & dat)
{
// use the bookkeeping root as the temporary directory.
+#if defined(RSE) /* alt-book-keeping-root */
+ if (directory_exists(alt_bookkeeping_root)) {
+ assert_path_is_directory(alt_bookkeeping_root);
+ write_data_impl(path, dat, alt_bookkeeping_root, false);
+ }
+ else {
+#endif
assert_path_is_directory(bookkeeping_root);
write_data_impl(path, dat, bookkeeping_root, false);
+#if defined(RSE) /* alt-book-keeping-root */
+ }
+#endif
}
void
write_data(bookkeeping_path const & path, data const & dat)
{
// use the bookkeeping root as the temporary directory.
+#if defined(RSE) /* alt-book-keeping-root */
+ if (directory_exists(alt_bookkeeping_root)) {
+ assert_path_is_directory(alt_bookkeeping_root);
+ write_data_impl(path, dat, alt_bookkeeping_root, false);
+ }
+ else {
+#endif
assert_path_is_directory(bookkeeping_root);
write_data_impl(path, dat, bookkeeping_root, false);
+#if defined(RSE) /* alt-book-keeping-root */
+ }
+#endif
}
void
===================================================================
Index: lua_hooks.cc
--- lua_hooks.cc d4f06492ebfd19893156cf0021b7afef29009332
+++ lua_hooks.cc 1041f875567d43f4afd0c5e68c10f96ebecfd219
@@ -224,7 +224,11 @@ lua_hooks::load_rcfiles(options & opts)
{
load_rcfile(opts.conf_dir / "monotonerc", false);
}
+#if defined(RSE) /* alt-book-keeping-root */
+ load_rcfile((directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / "monotonerc", false);
+#else
load_rcfile(bookkeeping_root / "monotonerc", false);
+#endif
}
// Command-line rcfiles override even that.
===================================================================
Index: luaext_platform.cc
--- luaext_platform.cc b22b5f7fa127055e909280379694c1635f4923ff
+++ luaext_platform.cc 24765cd8252f31a829d450ef92e002e615c98f9d
@@ -14,6 +14,9 @@
#include <cstdlib>
#include "platform.hh"
+#if defined(RSE) /* lua-rel-path */
+#include "paths.hh"
+#endif
using std::malloc;
using std::free;
@@ -185,6 +188,15 @@ LUAEXT(get_pid, )
return 1;
}
+#if defined(RSE) /* lua-rel-path */
+LUAEXT(workspace_relpath, )
+{
+ std::string str = workspace_initial_relative_path();
+ lua_pushlstring(LS, str.c_str(), str.size());
+ return 1;
+}
+#endif
+
// Local Variables:
// mode: C++
// fill-column: 76
===================================================================
Index: merge_roster.cc
--- merge_roster.cc 9c8e34b5521bde6f9a38f2996ce0edf51273e98d
+++ merge_roster.cc e653e463f7351026b9c90f32962e44f6f316a77c
@@ -724,6 +724,20 @@ roster_merge(roster_t const & left_paren
result.roster.detach_node(n->self);
result.invalid_name_conflicts.push_back(conflict);
}
+#if defined(RSE) /* alt-book-keeping-root */
+ if (result_root->has_child(alt_bookkeeping_root_component))
+ {
+ invalid_name_conflict conflict;
+ node_t n = result_root->get_child(alt_bookkeeping_root_component);
+ conflict.nid = n->self;
+ conflict.parent_name.first = n->parent;
+ conflict.parent_name.second = n->name;
+ I(n->name == alt_bookkeeping_root_component);
+
+ result.roster.detach_node(n->self);
+ result.invalid_name_conflicts.push_back(conflict);
+ }
+#endif
}
}
===================================================================
Index: migrate_work.cc
--- migrate_work.cc 2a8658dad954b975e65d3ceaf5df608007bfe841
+++ migrate_work.cc dc14b6fd1d3f80df37ae42f9df1be1253f085724
@@ -56,9 +56,18 @@ get_workspace_format()
{
unsigned int format;
bookkeeping_path f_path = bookkeeping_root / "format";
+#if defined(RSE) /* alt-book-keeping-root */
+ bookkeeping_path alt_f_path = alt_bookkeeping_root / "format";
+ if (!file_exists(f_path) && !file_exists(alt_f_path))
+#else
if (!file_exists(f_path))
+#endif
{
+#if defined(RSE) /* alt-book-keeping-root */
+ if (directory_exists(bookkeeping_root) || directory_exists(alt_bookkeeping_root))
+#else
if (directory_exists(bookkeeping_root))
+#endif
format = 1;
else if (directory_exists(file_path() / old_bookkeeping_root_component))
format = 0;
@@ -70,7 +79,11 @@ get_workspace_format()
data f_dat;
try
{
+#if defined(RSE) /* alt-book-keeping-root */
+ read_data(file_exists(alt_f_path) ? alt_f_path : f_path, f_dat);
+#else
read_data(f_path, f_dat);
+#endif
format = lexical_cast<unsigned int>(remove_ws(f_dat()));
}
catch (exception & e)
@@ -82,7 +95,11 @@ get_workspace_format()
if (format == 1)
{
W(F("_MTN/format should not exist in a format 1 workspace; corrected"));
+#if defined(RSE) /* alt-book-keeping-root */
+ delete_file(file_exists(alt_f_path) ? alt_f_path : f_path);
+#else
delete_file(f_path);
+#endif
}
}
return format;
@@ -92,6 +109,9 @@ workspace::write_format()
workspace::write_format()
{
bookkeeping_path f_path = bookkeeping_root / "format";
+#if defined(RSE) /* alt-book-keeping-root */
+ bookkeeping_path alt_f_path = alt_bookkeeping_root / "format";
+#endif
// one or other side of this conditional will always be dead code, but
// both sides should be preserved, to document all historical formats.
// N.B. this will _not_ do the right thing for format 0. Which is fine.
@@ -99,11 +119,20 @@ workspace::write_format()
{
if (file_exists(f_path))
delete_file(f_path);
+#if defined(RSE) /* alt-book-keeping-root */
+ if (file_exists(alt_f_path))
+ delete_file(alt_f_path);
+#endif
}
else
{
data f_dat(lexical_cast<string>(current_workspace_format) + "\n",
origin::workspace);
+#if defined(RSE) /* alt-book-keeping-root */
+ if (directory_exists(alt_bookkeeping_root))
+ write_data(alt_f_path, f_dat);
+ else
+#endif
write_data(f_path, f_dat);
}
}
@@ -186,7 +215,11 @@ migrate_1_to_2()
// information, and _MTN/work does not exist; also, there may be more than
// one parent revision, but we do not have to worry about that here.
+#if defined(RSE) /* alt-book-keeping-root */
+ bookkeeping_path rev_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / "revision";
+#else
bookkeeping_path rev_path = bookkeeping_root / "revision";
+#endif
data base_rev_data; MM(base_rev_data);
try
{
@@ -203,7 +236,11 @@ migrate_1_to_2()
cset workcs;
MM(workcs);
+#if defined(RSE) /* alt-book-keeping-root */
+ bookkeeping_path workcs_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / "work";
+#else
bookkeeping_path workcs_path = bookkeeping_root / "work";
+#endif
bool delete_workcs = false;
if (file_exists(workcs_path))
{
===================================================================
Index: options_list.hh
--- options_list.hh 521e90001833b8023276b7cedd0ed4b3253c1fd4
+++ options_list.hh e58b1dbae2c4089d3fbfed73f5a9981b9fd02b1e
@@ -331,6 +331,24 @@ OPTION(diff_options, with_header, false,
without_header = false;
}
#endif
+#if defined(RSE) /* cosmetics-diff-and-log */
+OPTVAR(diff_options, bool, no_show_header, false)
+OPTION(diff_options, no_show_header, false, "no-show-header",
+ gettext_noop("do not show the summary header"))
+#ifdef option_bodies
+{
+ no_show_header = true;
+}
+#endif
+OPTVAR(diff_options, bool, no_show_separator, false)
+OPTION(diff_options, no_show_separator, false, "no-show-separator",
+ gettext_noop("do not show the separator line"))
+#ifdef option_bodies
+{
+ no_show_separator = true;
+}
+#endif
+#endif
OPT(diffs, "diffs", bool, false, gettext_noop("print diffs along with logs"))
#ifdef option_bodies
===================================================================
Index: paths.cc
--- paths.cc defa5bd893d6db66107e50122713ee2769ce8d15
+++ paths.cc ca77119868c66526ccb6c6e024f9c242075774ff
@@ -231,7 +231,11 @@ in_bookkeeping_dir(string const & path)
static inline bool
in_bookkeeping_dir(string const & path)
{
+#if defined(RSE) /* alt-book-keeping-root */
+ if (path.empty() || (path[0] != '_' && path[0] != '.'))
+#else
if (path.empty() || (path[0] != '_'))
+#endif
return false;
if (path.size() == 1 || (path[1] != 'M' && path[1] != 'm'))
return false;
@@ -1024,6 +1028,9 @@ find_and_go_to_workspace(string const &
// first look for the current name of the bookkeeping directory.
// if we don't find it, look for it under the old name, so that
// migration has a chance to work.
+#if defined(RSE) /* alt-book-keeping-root */
+ if (!find_bookdir(root, alt_bookkeeping_root_component, current, removed))
+#endif
if (!find_bookdir(root, bookkeeping_root_component, current, removed))
if (!find_bookdir(root, old_bookkeeping_root_component, current, removed))
return false;
@@ -1054,6 +1061,13 @@ mark_std_paths_used(void)
initial_rel_path.get();
}
+#if defined(RSE) /* lua-rel-path */
+string workspace_initial_relative_path(void)
+{
+ return initial_rel_path.get();
+}
+#endif
+
///////////////////////////////////////////////////////////////////////////
// utility used by migrate_ancestry
///////////////////////////////////////////////////////////////////////////
===================================================================
Index: paths.hh
--- paths.hh e92b013f510afba1da74ab8f47a8f2fa799b3b5c
+++ paths.hh 38da34092ece2d3f80317b97197630711c05e393
@@ -351,6 +351,15 @@ private:
// for migration
#define old_bookkeeping_root_component (path_component("MT"))
+#if defined(RSE) /* alt-book-keeping-root */
+#ifndef MTN_ALT_BKROOT
+#define MTN_ALT_BKROOT ".mtn"
+#endif
+#define MTN_ALT_BKROOT_ARG (getenv("MTN_BKROOT") != NULL ? getenv("MTN_BKROOT") : MTN_ALT_BKROOT)
+#define alt_bookkeeping_root (bookkeeping_path(MTN_ALT_BKROOT_ARG))
+#define alt_bookkeeping_root_component (path_component(MTN_ALT_BKROOT_ARG))
+#endif
+
// this will always be an absolute path
class system_path : public any_path
{
@@ -473,8 +482,12 @@ find_new_path_for(std::map<file_path, fi
find_new_path_for(std::map<file_path, file_path> const & renames,
file_path const & old_path);
+#if defined(RSE) /* lua-rel-path */
+std::string workspace_initial_relative_path(void);
#endif
+#endif
+
// Local Variables:
// mode: C++
// fill-column: 76
===================================================================
Index: std_hooks.lua
--- std_hooks.lua 8d713fef5bf9921b78ac24e07f6d837524e35e9a
+++ std_hooks.lua 1c5fe914add9d8608b50cab633592ad5165688f3
@@ -304,6 +304,15 @@ function edit_comment(basetext, user_log
if user_log_message == "" or string.sub(user_log_message, -1) ~= "\n" then
tmp:write("\n")
end
+ -- #if defined(RSE) /* dot-mtn-message */
+ local template_log_message = read_contents_of_file(".mtn-message", "r")
+ if template_log_message ~= nil then
+ tmp:write(template_log_message)
+ if template_log_message == "" or string.sub(template_log_message, -1) ~= "\n" then
+ tmp:write("\n")
+ end
+ end
+ -- #endif
tmp:write(basetext)
io.close(tmp)
@@ -1442,3 +1451,267 @@ end
return false
end
+
+-- #if defined(RSE) /* extra-command */
+
+-- extra command: "mtn fuse REVISION"
+register_command(
+ "fuse", "REVISION",
+ "Fuse revision into workspace with conflict markers.",
+ "Fuse the specified revision into the current workspace by merging " ..
+ "the revision into the workspace while providing inline conflict " ..
+ "markers for manually resolving the conflicts in the workspace " ..
+ "before comitting the conflicts-resolved workspace as the new " ..
+ "merged revision.",
+ "command_fuse"
+)
+function command_fuse(revision)
+ if revision == nil then
+ io.stderr:write("mtn: fuse: ERROR: revision not given\n")
+ return
+ end
+ if program_exists_in_path("mtn") == 0 then
+ io.stderr:write("mtn: fuse: ERROR: require Monotone command \"mtn\" in PATH\n")
+ return
+ end
+ mtn_automate("get_option", "branch") -- make sure we have a valid workspace
+ local cmd =
+ "MTN_MERGE=diffutils " ..
+ "MTN_MERGE_DIFFUTILS=\"partial,diff3opts=-E\" " ..
+ "mtn " .. "merge_into_workspace " .. revision
+ local rc = execute("sh", "-c", cmd)
+ if rc ~= 0 then
+ io.stderr:write("mtn: fuse: ERROR: failed to execute command \"" .. cmd .. "\"\n")
+ end
+end
+
+-- extra command: "mtn conflicts"
+register_command(
+ "conflicts", "",
+ "Lists files in workspace containing conflict markers.",
+ "Lists all files in the current workspace containing the " ..
+ "conflict markers produced by GNU diffutils' \"diff3\" " ..
+ "command. This indicates still unresolved merge conflicts.",
+ "command_conflicts"
+)
+function command_conflicts()
+ if program_exists_in_path("egrep") == 0 then
+ io.stderr:write("mtn: conflicts: ERROR: require GNU grep command \"egrep\" in PATH\n")
+ return
+ end
+ mtn_automate("get_option", "branch") -- make sure we have a valid workspace
+ local rc = execute(
+ "egrep",
+ "--files-with-matches",
+ "--recursive",
+ "^(<<<<<<<|=======|>>>>>>>) ",
+ "."
+ )
+end
+
+-- extra command: "mtn rev[ision] REVISION [ANCESTOR-REVISION]"
+register_command(
+ "revision", "REVISION [ANCESTOR-REVISION]",
+ "Shows summary information about revision(s)",
+ "Shows summary information about a particular revision " ..
+ "(or a range of revisions in case an ancestor revision is also specified). " ..
+ "This is just a convenience wrapper command around \"mtn log --diffs\".",
+ "command_revision"
+)
+alias_command(
+ "revision",
+ "rev"
+)
+function command_revision(revision, ancestor)
+ if revision == nil then
+ io.stderr:write("mtn: revision: ERROR: no revision specified\n")
+ return
+ end
+ if ancestor == nil then
+ ancestor = revision
+ end
+ mtn_automate("get_option", "branch") -- make sure we have a valid workspace
+ execute("mtn", "log", "--diffs", "--no-graph", "--from", ancestor, "--to", revision)
+ if rc ~= 0 then
+ io.stderr:write("mtn: revision: ERROR: failed to execute\n")
+ end
+end
+
+-- extra command: "mtn base {upgrade|diff|integrate}"
+register_command(
+ "base", "fork|upgrade|diff|integrate [BRANCHNAME|FILENAME]",
+ "Forks, upgrades, compares or integrates current branch from/against/into base branch",
+ "Forks a new branch from the current branch, " ..
+ "upgrade current branch from base branch, " ..
+ "or compares current branch against base branch, " ..
+ "or integrates current branch into base branch. " ..
+ "The base branch has to be stored either in the " ..
+ "\"mtn:base\" attribute of the root directory or in a \".mtn-base\" " ..
+ "file in the root directory.",
+ "command_base"
+)
+function command_base(op, arg)
+ -- sanity check command line
+ if op == nil then
+ io.stderr:write("mtn: base: ERROR: no operation specified\n")
+ return
+ end
+ if op ~= "fork" and op ~= "upgrade" and op ~= "diff" and op ~= "integrate" then
+ io.stderr:write("mtn: base: ERROR: either \"fork\", \"upgrade\", or \"diff\" or \"integrate\" operation has to be specified\n")
+ return
+ end
+ if op == "fork" and arg == nil then
+ io.stderr:write("mtn: base: ERROR: BRANCHNAME argument missing for \"fork\" operation\n")
+ return
+ end
+ if op == "upgrade" and arg ~= nil then
+ io.stderr:write("mtn: base: ERROR: argument not valid for \"upgrade\" operation\n")
+ return
+ end
+ if op == "integrate" and arg ~= nil then
+ io.stderr:write("mtn: base: ERROR: argument not valid for \"integrate\" operation\n")
+ return
+ end
+
+ -- determine current branch of workspace
+ local branch_this = nil
+ local rc, txt = mtn_automate("get_option", "branch")
+ if txt ~= nil then
+ branch_this = string.match(txt, "^%s*(%S+)%s*$")
+ end
+ if branch_this == nil then
+ io.stderr:write("mtn: base: ERROR: failed to determine current branch\n")
+ return
+ end
+
+ -- determine base branch of workspace
+ local branch_base = nil
+ if op == "upgrade" or op == "diff" or op == "integrate" then
+ local rc, txt = mtn_automate("get_attributes", ".")
+ if txt ~= nil then
+ branch_base = string.match(txt, "attr%s+\"mtn:base\"%s+\"([^\"]+)\"")
+ end
+ if branch_base == nil then
+ local txt = read_contents_of_file(".mtn-base", "r")
+ if txt ~= nil then
+ branch_base = string.match(txt, "^%s*(%S+)%s*$")
+ end
+ end
+ if branch_base == nil then
+ io.stderr:write("mtn: base: ERROR: failed to determine base branch\n")
+ return
+ end
+ end
+
+ -- dispatch according to operation
+ if op == "fork" then
+ -- fork new branch from current branch
+ io.stderr:write("mtn: base: fork current branch \"" .. branch_this .. "\" into new branch \"" .. arg .. "\"\n")
+ fh = io.open(".mtn-base", "w")
+ fh:write(branch_this)
+ io.close(fh)
+ local rc, txt = mtn_automate("get_attributes", ".mtn-base")
+ if rc ~= 0 then
+ -- .mtn-base still not existing in current branch
+ local rc = execute("mtn", "add", ".mtn-base")
+ if rc ~= 0 then
+ io.stderr:write("mtn: base: ERROR: failed to execute \"mtn add\"\n")
+ return
+ end
+ end
+ rc = execute("mtn", "commit", "-m", "[auto-commit] add hint-file \".mtn-base\" to branch \"" .. arg .. "\"", "-b", arg, ".mtn-base")
+ if rc ~= 0 then
+ io.stderr:write("mtn: base: ERROR: failed to execute \"mtn commit\"\n")
+ return
+ end
+ elseif op == "upgrade" then
+ -- upgrade current branch by merging in revisions of base branch
+ io.stderr:write("mtn: base: upgrade current branch \"" .. branch_this .. "\" from base branch \"" .. branch_base .. "\"\n")
+ local rc = execute("mtn", "propagate", branch_base, branch_this)
+ if rc ~= 0 then
+ io.stderr:write("mtn: base: ERROR: failed to execute \"mtn propagate\"\n")
+ return
+ end
+ rc = execute("mtn", "update")
+ if rc ~= 0 then
+ io.stderr:write("mtn: base: ERROR: failed to execute \"mtn update\"\n")
+ return
+ end
+ elseif op == "diff" then
+ -- upgrade current branch by merging in revisions of base branch
+ io.stderr:write("mtn: base: diff current branch \"" .. branch_this .. "\" against base branch \"" .. branch_base .. "\"\n")
+ local rc
+ if arg ~= nil then
+ if not string.sub(arg, 1, 1) ~= "/" then
+ arg = workspace_relpath() .. "/" .. arg
+ end
+ rc = execute("mtn", "diff", "-r", "h:" .. branch_base, "-r", "h:" .. branch_this, arg)
+ else
+ rc = execute("mtn", "diff", "-r", "h:" .. branch_base, "-r", "h:" .. branch_this)
+ end
+ if rc ~= 0 then
+ io.stderr:write("mtn: base: ERROR: failed to execute \"mtn diff\"\n")
+ return
+ end
+ elseif op == "integrate" then
+ -- integrate back current branch by merging its revision into the base branch
+ io.stderr:write("mtn: base: integrate current branch \"" .. branch_this .. "\" into base branch \"" .. branch_base .. "\"\n")
+ rc = execute("mtn", "rm", ".mtn-base")
+ rc = execute("mtn", "commit", "-m", "[auto-commit] remove hint-file \".mtn-base\" from branch \"" .. branch_this .. "\"", ".mtn-base")
+ if rc ~= 0 then
+ io.stderr:write("mtn: base: ERROR: failed to execute \"mtn commit\"\n")
+ return
+ end
+ local rc = execute("mtn", "propagate", branch_this, branch_base)
+ if rc ~= 0 then
+ io.stderr:write("mtn: base: ERROR: failed to execute \"mtn propagate\"\n")
+ return
+ end
+ local rc = execute("mtn", "update", "-b", branch_base, "-r", "h:" .. branch_base)
+ if rc ~= 0 then
+ io.stderr:write("mtn: base: ERROR: failed to execute \"mtn update\"\n")
+ return
+ end
+ end
+ return
+end
+
+-- extra command: "mtn init"
+register_command(
+ "init", "BRANCH",
+ "Place local directory under local version control.",
+ "Creates a new _MTN/mtn.db database and places the local " ..
+ "directory tree under version control using this database.",
+ "command_init"
+)
+function command_init(branch)
+ -- sanity check command line
+ if branch == nil then
+ io.stderr:write("mtn: init: ERROR: no branch specified\n")
+ return
+ end
+
+ -- create new database
+ execute("mtn", "--db=mtn.db", "db", "init")
+
+ -- place current directory under version control
+ execute("mtn", "--db=mtn.db", "setup", "-b", branch)
+
+ -- use alternative book-keeping directory name
+ execute("mv", "_MTN", ".mtn")
+
+ -- place database into book-keeping directory
+ execute("mv", "mtn.db", ".mtn/mtn.db")
+ local txt = read_contents_of_file(".mtn/options")
+ txt = string.gsub(txt, "database \"[^\"]*\"", "database \".mtn/mtn.db\"")
+ options = io.open(".mtn/options", "w")
+ options:write(txt)
+ io.close(options)
+
+ -- perform a simple operation so that Monotone
+ -- updates the book-keeping directory
+ execute("sh", "-c", "mtn stat >/dev/null 2>&1")
+end
+
+-- #endif
+
===================================================================
Index: unit-tests/merge_roster.cc
--- unit-tests/merge_roster.cc fd6d157c77b4f168bdc1ed29940beea69707e1a3
+++ unit-tests/merge_roster.cc 8ff5b6ffeab2c6b0f3a00e89e2f6c05c6de7f2ce
@@ -945,7 +945,12 @@ struct simple_invalid_name_conflict : pu
I(!result.is_clean());
invalid_name_conflict const & c = idx(result.invalid_name_conflicts, 0);
I(c.nid == bad_dir_nid);
+#if defined(RSE) /* alt-book-keeping-root */
+ I( c.parent_name == make_pair(new_root_nid, bookkeeping_root_component)
+ || c.parent_name == make_pair(new_root_nid, alt_bookkeeping_root_component));
+#else
I(c.parent_name == make_pair(new_root_nid, bookkeeping_root_component));
+#endif
// this tests it was detached, implicitly
result.roster.attach_node(bad_dir_nid, file_path_internal("dir_formerly_known_as__MTN"));
result.invalid_name_conflicts.pop_back();
===================================================================
Index: unit-tests/paths.cc
--- unit-tests/paths.cc f443111b016125fb2b00af638586853a68369ad9
+++ unit-tests/paths.cc c14f0b1d89ba65c86af3b3f1591aa7eb694ce126
@@ -531,7 +531,11 @@ static void check_bk_normalizes_to(char
static void check_bk_normalizes_to(char const * before, char const * after)
{
+#if defined(RSE) /* alt-book-keeping-root */
+ bookkeeping_path bp((directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / before);
+#else
bookkeeping_path bp(bookkeeping_root / before);
+#endif
L(FL("normalizing %s to %s (got %s)") % before % after % bp);
UNIT_TEST_CHECK(bp.as_external() == after);
UNIT_TEST_CHECK(bookkeeping_path(bp.as_internal(),
===================================================================
Index: work.cc
--- work.cc 4a27d0c0133f6cc04b06944afe080400095676e2
+++ work.cc b7d8a57ea2935bc09f2e2358fa96685dee44737b
@@ -60,42 +60,66 @@ get_revision_path(bookkeeping_path & m_p
static void
get_revision_path(bookkeeping_path & m_path)
{
+#if defined(RSE) /* alt-book-keeping-root */
+ m_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / revision_file_name;
+#else
m_path = bookkeeping_root / revision_file_name;
+#endif
L(FL("revision path is %s") % m_path);
}
static void
get_options_path(bookkeeping_path & o_path)
{
+#if defined(RSE) /* alt-book-keeping-root */
+ o_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / options_file_name;
+#else
o_path = bookkeeping_root / options_file_name;
+#endif
L(FL("options path is %s") % o_path);
}
static void
get_options_path(system_path const & workspace, system_path & o_path)
{
+#if defined(RSE) /* alt-book-keeping-root */
+ o_path = (directory_exists(workspace / alt_bookkeeping_root_component) ? (workspace / alt_bookkeeping_root_component) : (workspace / bookkeeping_root_component)) / options_file_name;
+#else
o_path = workspace / bookkeeping_root_component / options_file_name;
+#endif
L(FL("options path is %s") % o_path);
}
static void
get_inodeprints_path(bookkeeping_path & ip_path)
{
+#if defined(RSE) /* alt-book-keeping-root */
+ ip_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / inodeprints_file_name;
+#else
ip_path = bookkeeping_root / inodeprints_file_name;
+#endif
L(FL("inodeprints path is %s") % ip_path);
}
static void
get_user_log_path(bookkeeping_path & ul_path)
{
+#if defined(RSE) /* alt-book-keeping-root */
+ ul_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / user_log_file_name;
+#else
ul_path = bookkeeping_root / user_log_file_name;
+#endif
L(FL("user log path is %s") % ul_path);
}
static void
get_update_path(bookkeeping_path & update_path)
{
+#if defined(RSE) /* alt-book-keeping-root */
+ update_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / update_file_name;
+#else
update_path = bookkeeping_root / update_file_name;
+#endif
L(FL("update path is %s") % update_path);
}
@@ -113,7 +137,11 @@ directory_is_workspace(system_path const
{
// as far as the users of this function are concerned, a version 0
// workspace (MT directory instead of _MTN) does not count.
+#if defined(RSE) /* alt-book-keeping-root */
+ return (directory_exists(dir / alt_bookkeeping_root_component) || directory_exists(dir / bookkeeping_root_component));
+#else
return directory_exists(dir / bookkeeping_root_component);
+#endif
}
bool workspace::found;
@@ -146,13 +174,24 @@ workspace::create_workspace(options cons
go_to_workspace(new_dir);
mark_std_paths_used();
+#if defined(RSE) /* alt-book-keeping-root */
+ E(!(directory_exists(bookkeeping_root) || directory_exists(alt_bookkeeping_root)), origin::user,
+ F("monotone bookkeeping directory '%s' or '%s' already exists in '%s'")
+ % bookkeeping_root % alt_bookkeeping_root % new_dir);
+#else
E(!directory_exists(bookkeeping_root), origin::user,
F("monotone bookkeeping directory '%s' already exists in '%s'")
% bookkeeping_root % new_dir);
+#endif
L(FL("creating bookkeeping directory '%s' for workspace in '%s'")
% bookkeeping_root % new_dir);
+#if defined(RSE) /* alt-book-keeping-root */
+ if (getenv("MTN_BKROOT") != NULL)
+ mkdir_p(bookkeeping_path(getenv("MTN_BKROOT")));
+ else
+#endif
mkdir_p(bookkeeping_root);
workspace::found = true;
@@ -545,9 +584,16 @@ workspace::get_database_option(system_pa
external_key_name workspace_key;
system_path workspace_keydir;
+#if defined(RSE) /* alt-book-keeping-root */
+ system_path o_path = (( directory_exists(workspace / alt_bookkeeping_root_component)
+ ? (workspace / alt_bookkeeping_root_component)
+ : (workspace / bookkeeping_root_component))
+ / options_file_name);
+#else
system_path o_path = (workspace
/ bookkeeping_root_component
/ options_file_name);
+#endif
read_options_file(o_path,
workspace_database, workspace_branch,
workspace_key, workspace_keydir);
@@ -745,7 +791,11 @@ workspace::get_local_dump_path(bookkeepi
{
E(workspace::found, origin::user, F("workspace required but not found"));
+#if defined(RSE) /* alt-book-keeping-root */
+ d_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / local_dump_file_name;
+#else
d_path = bookkeeping_root / local_dump_file_name;
+#endif
L(FL("local dump path is %s") % d_path);
}
@@ -1170,7 +1220,11 @@ path_for_detached_nids()
static inline bookkeeping_path
path_for_detached_nids()
{
+#if defined(RSE) /* alt-book-keeping-root */
+ return (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / "detached";
+#else
return bookkeeping_root / "detached";
+#endif
}
static inline bookkeeping_path
@@ -1974,9 +2028,15 @@ workspace::perform_pivot_root(database &
E(is_dir_t(old_roster.get_node(new_root)), origin::user,
F("proposed new root directory '%s' is not a directory") % new_root);
{
+#if defined(RSE) /* alt-book-keeping-root */
+ E(!(new_roster.has_node(new_root / bookkeeping_root_component) || new_roster.has_node(new_root / alt_bookkeeping_root_component)), origin::user,
+ F("proposed new root directory '%s' contains illegal path %s or %s")
+ % new_root % bookkeeping_root % alt_bookkeeping_root);
+#else
E(!old_roster.has_node(new_root / bookkeeping_root_component), origin::user,
F("proposed new root directory '%s' contains illegal path %s")
% new_root % bookkeeping_root);
+#endif
}
{