monotone.patch.rse 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906
  1. This is the RSE patchset for the Monotone VCS.
  2. The patchset is entirely enclosed in...
  3. #if defined(RSE) /* <tag> */
  4. [...]
  5. #endif
  6. ...and this way can be clearly distinguished. The <tag> corresponds
  7. the following major changes it includes:
  8. o environment-variables:
  9. This adds the two environment variables MTN_DBFILE and MTN_KEYDIR as
  10. defaults for the (bootstrapping) mtn(1) command line options --db
  11. and --keydir. This allows you to provide values for them without
  12. having to pass the options all the time.
  13. o alt-book-keeping-root:
  14. This allows mtn(1) to accept an alternative book-keeping directory.
  15. The default still is "_MTN", but alternatively one can rename this
  16. to ".mtn". If one sets the environment variable "MTN_BKROOT" one can
  17. change ".mtn" to an arbitrary sub-directory name and additionally
  18. even force its use on workspace creation operations.
  19. o cosmetics-netsync:
  20. This is just a small cosmetics change. It reduces the annoying
  21. "doing anonymous pull; use -kKEYNAME if you need authentication" to
  22. just "doing anonymous pull" as mtn(1) doesn't have to teach people.
  23. That's for what the documentation is for.
  24. o cosmetics-stat:
  25. The workspace top-level directory is shown as "" instead of nothing.
  26. o cosmetics-diff-and-log:
  27. This cosmetically "improves" the output of "mtn diff" and "mtn
  28. log". For "mtn diff" The output of "mtn diff" now uses a separator
  29. line consisting of 67 (instead of 60) "=" characters to align
  30. with cvs(1)'s well known output. Additionally, two new command
  31. line options for "mtn diff" allow one to disable some outputs:
  32. "--no-show-header" disables the output of the redundant "#..."
  33. header lines at the top of the output and "--no-show-separator"
  34. disables the output of the separator line at all. The output of "mtn
  35. log" is improved by aligning the single-line certificate values and
  36. by indenting the file change information by just 4 instead of 8
  37. characters.
  38. o diff-index:
  39. This adds "Index:" lines to the output of "mtn diff" in order to
  40. align with the "svn diff" and "cvs diff" outputs. This also helps
  41. patch(1) to clearly identify the file to patch.
  42. o extra-commands:
  43. This adds "mtn fuse", "mtn conflicts", "mtn revision" and "mtn base"
  44. commands. They are all simple but convenient Lua wrappers.
  45. o dot-mtn-message:
  46. Support a ".mtn-message" file in the root-directory as a template
  47. for the commit messages.
  48. Ralf S. Engelschall
  49. rse@engelschall.com
  50. www.engelschall.com
  51. Index: app_state.cc
  52. --- app_state.cc 6be9949e433ff6166fd030b34d8eb2d3e18c10b6
  53. +++ app_state.cc ce1cdaffff8c14261ab0a22a16571a0737532bbb
  54. @@ -138,13 +138,24 @@ app_state::create_workspace(system_path
  55. go_to_workspace(new_dir);
  56. mark_std_paths_used();
  57. +#if defined(RSE) /* alt-book-keeping-root */
  58. + N(!(directory_exists(bookkeeping_root) || directory_exists(alt_bookkeeping_root)),
  59. + F("monotone bookkeeping directory '%s' or '%s' already exists in '%s'")
  60. + % bookkeeping_root % alt_bookkeeping_root % new_dir);
  61. +#else
  62. N(!directory_exists(bookkeeping_root),
  63. F("monotone bookkeeping directory '%s' already exists in '%s'")
  64. % bookkeeping_root % new_dir);
  65. +#endif
  66. L(FL("creating bookkeeping directory '%s' for workspace in '%s'")
  67. % bookkeeping_root % new_dir);
  68. +#if defined(RSE) /* alt-book-keeping-root */
  69. + if (getenv("MTN_BKROOT") != NULL)
  70. + mkdir_p(bookkeeping_path(getenv("MTN_BKROOT")));
  71. + else
  72. +#endif
  73. mkdir_p(bookkeeping_root);
  74. make_branch_sticky();
  75. Index: cmd_diff_log.cc
  76. --- cmd_diff_log.cc baea6a3047420da7d1cff17f2669f973e0643e56
  77. +++ cmd_diff_log.cc f17665eb2b1be7eaef00380fef3e6c170cd1c152
  78. @@ -96,6 +96,27 @@ print_indented_set(ostream & os,
  79. set<file_path> const & s,
  80. size_t max_cols)
  81. {
  82. +#if defined(RSE) /* cosmetics-diff-and-log */
  83. + size_t cols = 4;
  84. + os << " ";
  85. + for (set<file_path>::const_iterator i = s.begin();
  86. + i != s.end(); i++)
  87. + {
  88. + const string str = lexical_cast<string>(*i);
  89. + if (cols > 4 && cols + str.size() + 1 >= max_cols)
  90. + {
  91. + cols = 4;
  92. + os << "\n ";
  93. + }
  94. + else if (cols > 4) {
  95. + os << ' ';
  96. + cols += 1;
  97. + }
  98. + os << str;
  99. + cols += str.size();
  100. + }
  101. + os << '\n';
  102. +#else
  103. size_t cols = 8;
  104. os << " ";
  105. for (set<file_path>::const_iterator i = s.begin();
  106. @@ -113,6 +134,7 @@ print_indented_set(ostream & os,
  107. cols += str.size() + 1;
  108. }
  109. os << '\n';
  110. +#endif
  111. }
  112. void
  113. @@ -131,7 +153,11 @@ changes_summary::print(ostream & os, siz
  114. for (map<file_path, file_path>::const_iterator
  115. i = cs.nodes_renamed.begin();
  116. i != cs.nodes_renamed.end(); i++)
  117. +#if defined(RSE) /* cosmetics-diff-and-log */
  118. + os << " " << i->first
  119. +#else
  120. os << " " << i->first
  121. +#endif
  122. << " to " << i->second << '\n';
  123. }
  124. @@ -232,8 +258,13 @@ dump_diffs(cset const & cs,
  125. set<file_path> const & paths,
  126. bool limit_paths = false)
  127. {
  128. +#if defined(RSE) /* cosmetics-diff-and-log */
  129. + // 67 is somewhat arbitrary (CVS uses this), but less than 80
  130. + string patch_sep = string(67, '=');
  131. +#else
  132. // 60 is somewhat arbitrary, but less than 80
  133. string patch_sep = string(60, '=');
  134. +#endif
  135. for (map<file_path, file_id>::const_iterator
  136. i = cs.files_added.begin();
  137. @@ -242,6 +273,9 @@ dump_diffs(cset const & cs,
  138. if (limit_paths && paths.find(i->first) == paths.end())
  139. continue;
  140. +#if defined(RSE) /* cosmetics-diff-and-log */
  141. + if (!app.opts.no_show_separator)
  142. +#endif
  143. output << patch_sep << '\n';
  144. data unpacked;
  145. vector<string> lines;
  146. @@ -288,6 +322,9 @@ dump_diffs(cset const & cs,
  147. file_data f_old;
  148. data data_old, data_new;
  149. +#if defined(RSE) /* cosmetics-diff-and-log */
  150. + if (!app.opts.no_show_separator)
  151. +#endif
  152. output << patch_sep << '\n';
  153. app.db.get_file_version(delta_entry_src(i), f_old);
  154. @@ -503,6 +540,9 @@ CMD(diff, "diff", "di", CMD_REF(informat
  155. data summary;
  156. write_cset(included, summary);
  157. +#if defined(RSE) /* cosmetics-diff-and-log */
  158. + if (!app.opts.no_show_header) {
  159. +#endif
  160. vector<string> lines;
  161. split_into_lines(summary(), lines);
  162. cout << "#\n";
  163. @@ -518,6 +558,9 @@ CMD(diff, "diff", "di", CMD_REF(informat
  164. cout << "# " << _("no changes") << '\n';
  165. }
  166. cout << "#\n";
  167. +#if defined(RSE) /* cosmetics-diff-and-log */
  168. + }
  169. +#endif
  170. if (app.opts.diff_format == external_diff)
  171. {
  172. @@ -881,7 +924,11 @@ CMD(log, "log", "", CMD_REF(informative)
  173. else
  174. {
  175. out << string(65, '-') << '\n';
  176. +#if defined(RSE) /* cosmetics-diff-and-log */
  177. + out << "Revision: " << rid << '\n';
  178. +#else
  179. out << "Revision: " << rid << '\n';
  180. +#endif
  181. changes_summary csum;
  182. @@ -896,12 +943,21 @@ CMD(log, "log", "", CMD_REF(informative)
  183. for (set<revision_id>::const_iterator anc = ancestors.begin();
  184. anc != ancestors.end(); ++anc)
  185. +#if defined(RSE) /* cosmetics-diff-and-log */
  186. + out << "Ancestor: " << *anc << '\n';
  187. +
  188. + log_certs(out, app, rid, author_name, "Author: ", false);
  189. + log_certs(out, app, rid, date_name, "Date: ", false);
  190. + log_certs(out, app, rid, branch_name, "Branch: ", false);
  191. + log_certs(out, app, rid, tag_name, "Tag: ", false);
  192. +#else
  193. out << "Ancestor: " << *anc << '\n';
  194. log_certs(out, app, rid, author_name, "Author: ", false);
  195. log_certs(out, app, rid, date_name, "Date: ", false);
  196. log_certs(out, app, rid, branch_name, "Branch: ", false);
  197. log_certs(out, app, rid, tag_name, "Tag: ", false);
  198. +#endif
  199. if (!app.opts.no_files && !csum.cs.empty())
  200. {
  201. @@ -911,7 +967,11 @@ CMD(log, "log", "", CMD_REF(informative)
  202. }
  203. log_certs(out, app, rid, changelog_name, "ChangeLog: ", true);
  204. +#if defined(RSE) /* cosmetics-diff-and-log */
  205. + log_certs(out, app, rid, comment_name, "Comments: ", true);
  206. +#else
  207. log_certs(out, app, rid, comment_name, "Comments: ", true);
  208. +#endif
  209. }
  210. if (app.opts.diffs)
  211. Index: cmd_netsync.cc
  212. --- cmd_netsync.cc 92bc91c7137e339e086b3ab761f1aed5df203143
  213. +++ cmd_netsync.cc 06dde80e2d7cc9bf8c9413a3df408dbb4cf36110
  214. @@ -179,7 +179,11 @@ CMD(pull, "pull", "", CMD_REF(network),
  215. find_key_if_needed(addr, include_pattern, exclude_pattern, app, false);
  216. if (app.opts.signing_key() == "")
  217. +#if defined(RSE) /* cosmetics-netsync */
  218. + P(F("doing anonymous pull"));
  219. +#else
  220. P(F("doing anonymous pull; use -kKEYNAME if you need authentication"));
  221. +#endif
  222. std::list<utf8> uris;
  223. uris.push_back(addr);
  224. @@ -277,7 +281,11 @@ CMD(clone, "clone", "", CMD_REF(network)
  225. app.create_workspace(workspace_dir);
  226. if (internal_db)
  227. +#if defined(RSE) /* alt-book-keeping-root */
  228. + app.set_database(system_path((directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / ws_internal_db_file_name));
  229. +#else
  230. app.set_database(system_path(bookkeeping_root / ws_internal_db_file_name));
  231. +#endif
  232. else
  233. app.set_database(app.opts.dbname);
  234. @@ -299,7 +307,11 @@ CMD(clone, "clone", "", CMD_REF(network)
  235. app, false);
  236. if (app.opts.signing_key() == "")
  237. +#if defined(RSE) /* cosmetics-netsync */
  238. + P(F("doing anonymous pull"));
  239. +#else
  240. P(F("doing anonymous pull; use -kKEYNAME if you need authentication"));
  241. +#endif
  242. if (!app.db.var_exists(default_include_pattern_key)
  243. || app.opts.set_default)
  244. Index: cmd_ws_commit.cc
  245. --- cmd_ws_commit.cc e21e2bb8831ce7e62bc428cf32ae10931b5e73e8
  246. +++ cmd_ws_commit.cc 80856a59e293d7aa2bcc14cfce5896e1276a1921
  247. @@ -66,7 +66,14 @@ revision_summary(revision_t const & rev,
  248. for (set<file_path>::const_iterator i = cs.dirs_added.begin();
  249. i != cs.dirs_added.end(); ++i)
  250. +#if defined(RSE) /* cosmetics-stat */
  251. + if ((*i) == file_path())
  252. + out += (F(" added \"\"")).str() += '\n';
  253. + else
  254. + out += (F(" added %s") % *i).str() += '\n';
  255. +#else
  256. out += (F(" added %s") % *i).str() += '\n';
  257. +#endif
  258. for (map<file_path, file_id>::const_iterator i = cs.files_added.begin();
  259. i != cs.files_added.end(); ++i)
  260. @@ -1396,7 +1403,11 @@ CMD_NO_WORKSPACE(import, "import", "", C
  261. catch (...)
  262. {
  263. // clean up before rethrowing
  264. +#if defined(RSE) /* alt-book-keeping-root */
  265. + delete_dir_recursive(directory_exists(alt_bookkeeping_root) ? bookkeeping_root : bookkeeping_root);
  266. +#else
  267. delete_dir_recursive(bookkeeping_root);
  268. +#endif
  269. throw;
  270. }
  271. Index: diff_patch.cc
  272. --- diff_patch.cc 2d882bd69beabffdef24078ecae588118f8f51cb
  273. +++ diff_patch.cc d4d89f2eebbe0d2f7f42e6eb014c3960e5dccdb4
  274. @@ -1448,6 +1448,9 @@ make_diff(string const & filename1,
  275. {
  276. case unified_diff:
  277. {
  278. +#if defined(RSE) /* diff-index */
  279. + ost << "Index: " << filename2 << '\n';
  280. +#endif
  281. ost << "--- " << filename1 << '\t' << id1 << '\n';
  282. ost << "+++ " << filename2 << '\t' << id2 << '\n';
  283. @@ -1457,6 +1460,9 @@ make_diff(string const & filename1,
  284. }
  285. case context_diff:
  286. {
  287. +#if defined(RSE) /* diff-index */
  288. + ost << "Index: " << filename2 << '\n';
  289. +#endif
  290. ost << "*** " << filename1 << '\t' << id1 << '\n';
  291. ost << "--- " << filename2 << '\t' << id2 << '\n';
  292. Index: file_io.cc
  293. --- file_io.cc 358fb964dc42e7f936a136342b93bb3a4744d1b3
  294. +++ file_io.cc 6b452acaa58ca24fa5611ea3e6e82e83a7cf7552
  295. @@ -398,16 +398,36 @@ write_data(file_path const & path, data
  296. write_data(file_path const & path, data const & dat)
  297. {
  298. // use the bookkeeping root as the temporary directory.
  299. +#if defined(RSE) /* alt-book-keeping-root */
  300. + if (directory_exists(alt_bookkeeping_root)) {
  301. + assert_path_is_directory(alt_bookkeeping_root);
  302. + write_data_impl(path, dat, alt_bookkeeping_root, false);
  303. + }
  304. + else {
  305. +#endif
  306. assert_path_is_directory(bookkeeping_root);
  307. write_data_impl(path, dat, bookkeeping_root, false);
  308. +#if defined(RSE) /* alt-book-keeping-root */
  309. + }
  310. +#endif
  311. }
  312. void
  313. write_data(bookkeeping_path const & path, data const & dat)
  314. {
  315. // use the bookkeeping root as the temporary directory.
  316. +#if defined(RSE) /* alt-book-keeping-root */
  317. + if (directory_exists(alt_bookkeeping_root)) {
  318. + assert_path_is_directory(alt_bookkeeping_root);
  319. + write_data_impl(path, dat, alt_bookkeeping_root, false);
  320. + }
  321. + else {
  322. +#endif
  323. assert_path_is_directory(bookkeeping_root);
  324. write_data_impl(path, dat, bookkeeping_root, false);
  325. +#if defined(RSE) /* alt-book-keeping-root */
  326. + }
  327. +#endif
  328. }
  329. void
  330. Index: lua_hooks.cc
  331. --- lua_hooks.cc 26dbfb8306a7b7b4871f61877c7fd0f72abadfdd
  332. +++ lua_hooks.cc 87a5a20651f2010b1e08c38274b29e0e6434e077
  333. @@ -162,7 +162,11 @@ lua_hooks::workspace_rcfilename(bookkeep
  334. void
  335. lua_hooks::workspace_rcfilename(bookkeeping_path & file)
  336. {
  337. +#if defined(RSE) /* alt-book-keeping-root */
  338. + file = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / "monotonerc";
  339. +#else
  340. file = bookkeeping_root / "monotonerc";
  341. +#endif
  342. }
  343. Index: monotone.cc
  344. --- monotone.cc 8289cbcfbca10f561afa6e06bf279f6b70e93599
  345. +++ monotone.cc 2560f9465773c1178c539e51c66efe1a99109881
  346. @@ -211,12 +211,28 @@ cpp_main(int argc, char ** argv)
  347. if (!app.opts.dbname.empty())
  348. app.db.set_filename(app.opts.dbname);
  349. }
  350. +#if defined(RSE) /* environment-variables */
  351. + else
  352. + {
  353. + char *cp;
  354. + if ((cp = getenv("MTN_DBFILE")) != NULL)
  355. + app.db.set_filename(system_path(cp));
  356. + }
  357. +#endif
  358. if (app.opts.key_dir_given || app.opts.conf_dir_given)
  359. {
  360. if (!app.opts.key_dir.empty())
  361. app.keys.set_key_dir(app.opts.key_dir);
  362. }
  363. +#if defined(RSE) /* environment-variables */
  364. + else
  365. + {
  366. + char *cp;
  367. + if ((cp = getenv("MTN_KEYDIR")) != NULL)
  368. + app.keys.set_key_dir(system_path(cp));
  369. + }
  370. +#endif
  371. // at this point we allow a workspace (meaning search for it
  372. // and if found read _MTN/options, but don't use the data quite
  373. Index: options_list.hh
  374. --- options_list.hh 1f1eb3ce7a6a72870d0a42ef7f79b58eef621127
  375. +++ options_list.hh 82cddc1ff530f09a32cf7d2c58d6b9ef01449147
  376. @@ -178,6 +178,24 @@ OPTION(diff_options, no_show_encloser, f
  377. no_show_encloser = true;
  378. }
  379. #endif
  380. +#if defined(RSE) /* cosmetics-diff-and-log */
  381. +OPTVAR(diff_options, bool, no_show_header, false)
  382. +OPTION(diff_options, no_show_header, false, "no-show-header",
  383. + gettext_noop("do not show the summary header"))
  384. +#ifdef option_bodies
  385. +{
  386. + no_show_header = true;
  387. +}
  388. +#endif
  389. +OPTVAR(diff_options, bool, no_show_separator, false)
  390. +OPTION(diff_options, no_show_separator, false, "no-show-separator",
  391. + gettext_noop("do not show the separator line"))
  392. +#ifdef option_bodies
  393. +{
  394. + no_show_separator = true;
  395. +}
  396. +#endif
  397. +#endif
  398. OPT(diffs, "diffs", bool, false, gettext_noop("print diffs along with logs"))
  399. #ifdef option_bodies
  400. Index: paths.cc
  401. --- paths.cc d850c3efae62041b8003589817387e5877f63b01
  402. +++ paths.cc 30e8e5ea486bbbda2344474f7bfa86f0b152c438
  403. @@ -226,7 +226,11 @@ in_bookkeeping_dir(string const & path)
  404. static inline bool
  405. in_bookkeeping_dir(string const & path)
  406. {
  407. +#if defined(RSE) /* alt-book-keeping-root */
  408. + if (path.size() == 0 || (path[0] != '_' && path[0] != '.'))
  409. +#else
  410. if (path.size() == 0 || (path[0] != '_'))
  411. +#endif
  412. return false;
  413. if (path.size() == 1 || (path[1] != 'M' && path[1] != 'm'))
  414. return false;
  415. @@ -919,6 +923,9 @@ find_and_go_to_workspace(string const &
  416. // first look for the current name of the bookkeeping directory.
  417. // if we don't find it, look for it under the old name, so that
  418. // migration has a chance to work.
  419. +#if defined(RSE) /* alt-book-keeping-root */
  420. + if (!find_bookdir(root, alt_bookkeeping_root_component, current, removed))
  421. +#endif
  422. if (!find_bookdir(root, bookkeeping_root_component, current, removed))
  423. if (!find_bookdir(root, old_bookkeeping_root_component, current, removed))
  424. return false;
  425. Index: paths.hh
  426. --- paths.hh 7dd47155b2962d3e4f5fe8764b11c955791803fc
  427. +++ paths.hh d29c84938079b1571cc843c7b7c6c61e420421d7
  428. @@ -328,6 +328,15 @@ private:
  429. // for migration
  430. #define old_bookkeeping_root_component (path_component("MT"))
  431. +#if defined(RSE) /* alt-book-keeping-root */
  432. +#ifndef MTN_ALT_BKROOT
  433. +#define MTN_ALT_BKROOT ".mtn"
  434. +#endif
  435. +#define MTN_ALT_BKROOT_ARG (getenv("MTN_BKROOT") != NULL ? getenv("MTN_BKROOT") : MTN_ALT_BKROOT)
  436. +#define alt_bookkeeping_root (bookkeeping_path(MTN_ALT_BKROOT_ARG))
  437. +#define alt_bookkeeping_root_component (path_component(MTN_ALT_BKROOT_ARG))
  438. +#endif
  439. +
  440. // this will always be an absolute path
  441. class system_path : public any_path
  442. {
  443. Index: roster_merge.cc
  444. --- roster_merge.cc d565f9299ca85d77bd1d7f2a29196d7161f0ea08
  445. +++ roster_merge.cc 630d1821e0631e49557bea17008bf88093ec4aa8
  446. @@ -1273,6 +1273,20 @@ roster_merge(roster_t const & left_paren
  447. result.roster.detach_node(n->self);
  448. result.invalid_name_conflicts.push_back(conflict);
  449. }
  450. +#if defined(RSE) /* alt-book-keeping-root */
  451. + if (result_root->has_child(alt_bookkeeping_root_component))
  452. + {
  453. + invalid_name_conflict conflict;
  454. + node_t n = result_root->get_child(alt_bookkeeping_root_component);
  455. + conflict.nid = n->self;
  456. + conflict.parent_name.first = n->parent;
  457. + conflict.parent_name.second = n->name;
  458. + I(n->name == alt_bookkeeping_root_component);
  459. +
  460. + result.roster.detach_node(n->self);
  461. + result.invalid_name_conflicts.push_back(conflict);
  462. + }
  463. +#endif
  464. }
  465. }
  466. Index: std_hooks.lua
  467. --- std_hooks.lua 432725fc36dde06af213797306121385491fda0c
  468. +++ std_hooks.lua fc4aa2c8e1e8963817dea1a47b21f19ee7292b11
  469. @@ -284,6 +284,15 @@
  470. if user_log_message == "" or string.sub(user_log_message, -1) ~= "\n" then
  471. tmp:write("\n")
  472. end
  473. + -- #if defined(RSE) /* dot-mtn-message */
  474. + local template_log_message = read_contents_of_file(".mtn-message", "r")
  475. + if template_log_message ~= nil then
  476. + tmp:write(template_log_message)
  477. + if template_log_message == "" or string.sub(template_log_message, -1) ~= "\n" then
  478. + tmp:write("\n")
  479. + end
  480. + end
  481. + -- #endif
  482. tmp:write(basetext)
  483. io.close(tmp)
  484. @@ -1220,4 +1229,165 @@
  485. function push_netsync_notifier(notifier)
  486. return push_hook_functions(notifier)
  487. end
  488. -end
  489. \ No newline at end of file
  490. +end
  491. +
  492. +-- #if defined(RSE) /* extra-command */
  493. +
  494. +-- extra command: "mtn fuse REVISION"
  495. +register_command(
  496. + "fuse", "REVISION",
  497. + "Fuse revision into workspace with conflict markers.",
  498. + "Fuse the specified revision into the current workspace by merging " ..
  499. + "the revision into the workspace while providing inline conflict " ..
  500. + "markers for manually resolving the conflicts in the workspace " ..
  501. + "before comitting the conflicts-resolved workspace as the new " ..
  502. + "merged revision.",
  503. + "command_fuse"
  504. +)
  505. +function command_fuse(revision)
  506. + if revision == nil then
  507. + io.stderr:write("mtn: fuse: ERROR: revision not given\n")
  508. + return
  509. + end
  510. + if program_exists_in_path("mtn") == 0 then
  511. + io.stderr:write("mtn: fuse: ERROR: require Monotone command \"mtn\" in PATH\n")
  512. + return
  513. + end
  514. + mtn_automate("get_option", "branch") -- make sure we have a valid workspace
  515. + local cmd =
  516. + "MTN_MERGE=diffutils " ..
  517. + "MTN_MERGE_DIFFUTILS=\"partial,diff3opts=-E\" " ..
  518. + "mtn " .. "merge_into_workspace " .. revision
  519. + local rc = execute("sh", "-c", cmd)
  520. + if rc ~= 0 then
  521. + io.stderr:write("mtn: fuse: ERROR: failed to execute command \"" .. cmd .. "\"\n")
  522. + end
  523. +end
  524. +
  525. +-- extra command: "mtn conflicts"
  526. +register_command(
  527. + "conflicts", "",
  528. + "Lists files in workspace containing conflict markers.",
  529. + "Lists all files in the current workspace containing the " ..
  530. + "conflict markers produced by GNU diffutils' \"diff3\" " ..
  531. + "command. This indicates still unresolved merge conflicts.",
  532. + "command_conflicts"
  533. +)
  534. +function command_conflicts()
  535. + if program_exists_in_path("egrep") == 0 then
  536. + io.stderr:write("mtn: conflicts: ERROR: require GNU grep command \"egrep\" in PATH\n")
  537. + return
  538. + end
  539. + mtn_automate("get_option", "branch") -- make sure we have a valid workspace
  540. + local rc = execute(
  541. + "egrep",
  542. + "--files-with-matches",
  543. + "--recursive",
  544. + "^(<<<<<<<|=======|>>>>>>>) ",
  545. + "."
  546. + )
  547. +end
  548. +
  549. +-- extra command: "mtn rev[ision] REVISION [ANCESTOR-REVISION]"
  550. +register_command(
  551. + "revision", "REVISION [ANCESTOR-REVISION]",
  552. + "Shows summary information about revision(s)",
  553. + "Shows summary information about a particular revision " ..
  554. + "(or a range of revisions in case an ancestor revision is also specified). " ..
  555. + "This is just a convenience wrapper command around \"mtn log --diffs\".",
  556. + "command_revision"
  557. +)
  558. +alias_command(
  559. + "revision",
  560. + "rev"
  561. +)
  562. +function command_revision(revision, ancestor)
  563. + if revision == nil then
  564. + io.stderr:write("mtn: revision: ERROR: no revision specified\n")
  565. + return
  566. + end
  567. + if ancestor == nil then
  568. + ancestor = revision
  569. + end
  570. + mtn_automate("get_option", "branch") -- make sure we have a valid workspace
  571. + execute("mtn", "log", "--diffs", "--no-graph", "--from", ancestor, "--to", revision)
  572. + if rc ~= 0 then
  573. + io.stderr:write("mtn: revision: ERROR: failed to execute\n")
  574. + end
  575. +end
  576. +
  577. +-- extra command: "mtn base {upgrade|diff}"
  578. +register_command(
  579. + "base", "upgrade|diff",
  580. + "Upgrades or compares current branch against base branch",
  581. + "Upgrade current branch from base branch or compares current " ..
  582. + "branch against base branch. The base branch has to be stored " ..
  583. + "either in the \"mtn:base\" attribute of the root directory " ..
  584. + "or in a \".mtn-base\" file in the root directory.",
  585. + "command_base"
  586. +)
  587. +function command_base(op)
  588. + -- sanity check command line
  589. + if op == nil then
  590. + io.stderr:write("mtn: base: ERROR: no operation specified\n")
  591. + return
  592. + end
  593. + if op ~= "upgrade" and op ~= "diff" then
  594. + io.stderr:write("mtn: base: ERROR: either \"upgrade\" or \"diff\" operation has to be specified\n")
  595. + return
  596. + end
  597. +
  598. + -- determine current branch of workspace
  599. + local branch_this = nil
  600. + local rc, txt = mtn_automate("get_option", "branch")
  601. + if txt ~= nil then
  602. + branch_this = string.match(txt, "^%s*(%S+)%s*$")
  603. + end
  604. + if branch_this == nil then
  605. + io.stderr:write("mtn: base: ERROR: failed to determine current branch\n")
  606. + return
  607. + end
  608. +
  609. + -- determine base branch of workspace
  610. + local branch_base = nil
  611. + local rc, txt = mtn_automate("get_attributes", ".")
  612. + if txt ~= nil then
  613. + branch_base = string.match(txt, "attr%s+\"mtn:base\"%s+\"([^\"]+)\"")
  614. + end
  615. + if branch_base == nil then
  616. + local txt = read_contents_of_file(".mtn-base", "r")
  617. + if txt ~= nil then
  618. + branch_base = string.match(txt, "^%s*(%S+)%s*$")
  619. + end
  620. + end
  621. + if branch_base == nil then
  622. + io.stderr:write("mtn: base: ERROR: failed to determine base branch\n")
  623. + return
  624. + end
  625. +
  626. + -- dispatch according to operation
  627. + if op == "upgrade" then
  628. + -- upgrade current branch by merging in revisions of base branch
  629. + local rc = execute("mtn", "propagate", branch_base, branch_this)
  630. + if rc ~= 0 then
  631. + io.stderr:write("mtn: revision: ERROR: failed to execute \"mtn propagate\"\n")
  632. + return
  633. + end
  634. + rc = execute("mtn", "update")
  635. + if rc ~= 0 then
  636. + io.stderr:write("mtn: revision: ERROR: failed to execute \"mtn update\"\n")
  637. + return
  638. + end
  639. + elseif op == "diff" then
  640. + -- upgrade current branch by merging in revisions of base branch
  641. + local rc = execute("mtn", "diff", "-r", "h:" .. branch_base, "-r", "h:" .. branch_this)
  642. + if rc ~= 0 then
  643. + io.stderr:write("mtn: revision: ERROR: failed to execute \"mtn diff\"\n")
  644. + return
  645. + end
  646. + end
  647. + return
  648. +end
  649. +
  650. +-- #endif
  651. +
  652. Index: work.cc
  653. --- work.cc bcea6fae446e61352e4a12e0259a9094970a9829
  654. +++ work.cc 1282657792888a3159211df49da6afa167e8cbb4
  655. @@ -53,28 +53,44 @@ get_revision_path(bookkeeping_path & m_p
  656. static void
  657. get_revision_path(bookkeeping_path & m_path)
  658. {
  659. +#if defined(RSE) /* alt-book-keeping-root */
  660. + m_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / revision_file_name;
  661. +#else
  662. m_path = bookkeeping_root / revision_file_name;
  663. +#endif
  664. L(FL("revision path is %s") % m_path);
  665. }
  666. static void
  667. get_options_path(bookkeeping_path & o_path)
  668. {
  669. +#if defined(RSE) /* alt-book-keeping-root */
  670. + o_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / options_file_name;
  671. +#else
  672. o_path = bookkeeping_root / options_file_name;
  673. +#endif
  674. L(FL("options path is %s") % o_path);
  675. }
  676. static void
  677. get_options_path(system_path const & workspace, system_path & o_path)
  678. {
  679. +#if defined(RSE) /* alt-book-keeping-root */
  680. + o_path = (directory_exists(workspace / alt_bookkeeping_root_component) ? (workspace / alt_bookkeeping_root_component) : (workspace / bookkeeping_root_component)) / options_file_name;
  681. +#else
  682. o_path = workspace / bookkeeping_root_component / options_file_name;
  683. +#endif
  684. L(FL("options path is %s") % o_path);
  685. }
  686. static void
  687. get_inodeprints_path(bookkeeping_path & ip_path)
  688. {
  689. +#if defined(RSE) /* alt-book-keeping-root */
  690. + ip_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / inodeprints_file_name;
  691. +#else
  692. ip_path = bookkeeping_root / inodeprints_file_name;
  693. +#endif
  694. L(FL("inodeprints path is %s") % ip_path);
  695. }
  696. @@ -205,7 +221,11 @@ workspace::get_user_log_path(bookkeeping
  697. void
  698. workspace::get_user_log_path(bookkeeping_path & ul_path)
  699. {
  700. +#if defined(RSE) /* alt-book-keeping-root */
  701. + ul_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / user_log_file_name;
  702. +#else
  703. ul_path = bookkeeping_root / user_log_file_name;
  704. +#endif
  705. L(FL("user log path is %s") % ul_path);
  706. }
  707. @@ -387,7 +407,11 @@ workspace::get_local_dump_path(bookkeepi
  708. void
  709. workspace::get_local_dump_path(bookkeeping_path & d_path)
  710. {
  711. +#if defined(RSE) /* alt-book-keeping-root */
  712. + d_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / local_dump_file_name;
  713. +#else
  714. d_path = bookkeeping_root / local_dump_file_name;
  715. +#endif
  716. L(FL("local dump path is %s") % d_path);
  717. }
  718. @@ -747,7 +771,11 @@ path_for_detached_nids()
  719. static inline bookkeeping_path
  720. path_for_detached_nids()
  721. {
  722. +#if defined(RSE) /* alt-book-keeping-root */
  723. + return (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / "detached";
  724. +#else
  725. return bookkeeping_root / "detached";
  726. +#endif
  727. }
  728. static inline bookkeeping_path
  729. @@ -1483,9 +1511,15 @@ workspace::perform_pivot_root(file_path
  730. N(is_dir_t(new_roster.get_node(new_root)),
  731. F("proposed new root directory '%s' is not a directory") % new_root);
  732. {
  733. +#if defined(RSE) /* alt-book-keeping-root */
  734. + N(!(new_roster.has_node(new_root / bookkeeping_root_component) || new_roster.has_node(new_root / alt_bookkeeping_root_component)),
  735. + F("proposed new root directory '%s' contains illegal path %s or %s")
  736. + % new_root % bookkeeping_root % alt_bookkeeping_root);
  737. +#else
  738. N(!new_roster.has_node(new_root / bookkeeping_root_component),
  739. F("proposed new root directory '%s' contains illegal path %s")
  740. % new_root % bookkeeping_root);
  741. +#endif
  742. }
  743. {
  744. Index: work_migration.cc
  745. --- work_migration.cc 3d58c3332cd195309eacf5cc52d4e88ad66a6c81
  746. +++ work_migration.cc f044e25cc757899f97d413f3fe109a9bafe73553
  747. @@ -55,9 +55,18 @@ get_ws_format()
  748. {
  749. unsigned int format;
  750. bookkeeping_path f_path = bookkeeping_root / "format";
  751. +#if defined(RSE) /* alt-book-keeping-root */
  752. + bookkeeping_path alt_f_path = alt_bookkeeping_root / "format";
  753. + if (!file_exists(f_path) && !file_exists(alt_f_path))
  754. +#else
  755. if (!file_exists(f_path))
  756. +#endif
  757. {
  758. +#if defined(RSE) /* alt-book-keeping-root */
  759. + if (directory_exists(bookkeeping_root) || directory_exists(alt_bookkeeping_root))
  760. +#else
  761. if (directory_exists(bookkeeping_root))
  762. +#endif
  763. format = 1;
  764. else if (directory_exists(file_path() / old_bookkeeping_root_component))
  765. format = 0;
  766. @@ -69,7 +78,11 @@ get_ws_format()
  767. data f_dat;
  768. try
  769. {
  770. +#if defined(RSE) /* alt-book-keeping-root */
  771. + read_data(file_exists(alt_f_path) ? alt_f_path : f_path, f_dat);
  772. +#else
  773. read_data(f_path, f_dat);
  774. +#endif
  775. format = lexical_cast<unsigned int>(remove_ws(f_dat()));
  776. }
  777. catch (exception & e)
  778. @@ -80,7 +93,11 @@ get_ws_format()
  779. if (format == 1)
  780. {
  781. W(F("_MTN/format should not exist in a format 1 workspace; corrected"));
  782. +#if defined(RSE) /* alt-book-keeping-root */
  783. + delete_file(file_exists(alt_f_path) ? alt_f_path : f_path);
  784. +#else
  785. delete_file(f_path);
  786. +#endif
  787. }
  788. }
  789. return format;
  790. @@ -90,6 +107,9 @@ workspace::write_ws_format()
  791. workspace::write_ws_format()
  792. {
  793. bookkeeping_path f_path = bookkeeping_root / "format";
  794. +#if defined(RSE) /* alt-book-keeping-root */
  795. + bookkeeping_path alt_f_path = alt_bookkeeping_root / "format";
  796. +#endif
  797. // one or other side of this conditional will always be dead code, but
  798. // both sides should be preserved, to document all historical formats.
  799. // N.B. this will _not_ do the right thing for format 0. Which is fine.
  800. @@ -97,10 +117,19 @@ workspace::write_ws_format()
  801. {
  802. if (file_exists(f_path))
  803. delete_file(f_path);
  804. +#if defined(RSE) /* alt-book-keeping-root */
  805. + if (file_exists(alt_f_path))
  806. + delete_file(alt_f_path);
  807. +#endif
  808. }
  809. else
  810. {
  811. data f_dat(lexical_cast<string>(current_workspace_format) + "\n");
  812. +#if defined(RSE) /* alt-book-keeping-root */
  813. + if (directory_exists(alt_bookkeeping_root))
  814. + write_data(alt_f_path, f_dat);
  815. + else
  816. +#endif
  817. write_data(f_path, f_dat);
  818. }
  819. }
  820. @@ -180,7 +209,11 @@ migrate_1_to_2()
  821. // information, and _MTN/work does not exist; also, there may be more than
  822. // one parent revision, but we do not have to worry about that here.
  823. +#if defined(RSE) /* alt-book-keeping-root */
  824. + bookkeeping_path rev_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / "revision";
  825. +#else
  826. bookkeeping_path rev_path = bookkeeping_root / "revision";
  827. +#endif
  828. data base_rev_data; MM(base_rev_data);
  829. try
  830. {
  831. @@ -196,7 +229,11 @@ migrate_1_to_2()
  832. cset workcs;
  833. MM(workcs);
  834. +#if defined(RSE) /* alt-book-keeping-root */
  835. + bookkeeping_path workcs_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / "work";
  836. +#else
  837. bookkeeping_path workcs_path = bookkeeping_root / "work";
  838. +#endif
  839. bool delete_workcs = false;
  840. if (file_exists(workcs_path))
  841. {