monotone.patch.rse 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070
  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. ===================================================================
  52. Index: cmd_diff_log.cc
  53. --- cmd_diff_log.cc fd455eacd212d63aa201035e9417b9cf726f498b
  54. +++ cmd_diff_log.cc 234ce11a43478c6ed8fb9b711f31039e3609bd60
  55. @@ -100,6 +100,27 @@ print_indented_set(ostream & os,
  56. set<file_path> const & s,
  57. size_t max_cols)
  58. {
  59. +#if defined(RSE) /* cosmetics-diff-and-log */
  60. + size_t cols = 4;
  61. + os << " ";
  62. + for (set<file_path>::const_iterator i = s.begin();
  63. + i != s.end(); i++)
  64. + {
  65. + const string str = lexical_cast<string>(*i);
  66. + if (cols > 4 && cols + str.size() + 1 >= max_cols)
  67. + {
  68. + cols = 4;
  69. + os << "\n ";
  70. + }
  71. + else if (cols > 4) {
  72. + os << ' ';
  73. + cols += 1;
  74. + }
  75. + os << str;
  76. + cols += str.size();
  77. + }
  78. + os << '\n';
  79. +#else
  80. size_t cols = 8;
  81. os << " ";
  82. for (set<file_path>::const_iterator i = s.begin();
  83. @@ -117,6 +138,7 @@ print_indented_set(ostream & os,
  84. cols += str.size() + 1;
  85. }
  86. os << '\n';
  87. +#endif
  88. }
  89. void
  90. @@ -135,7 +157,11 @@ changes_summary::print(ostream & os, siz
  91. for (map<file_path, file_path>::const_iterator
  92. i = cs.nodes_renamed.begin();
  93. i != cs.nodes_renamed.end(); i++)
  94. +#if defined(RSE) /* cosmetics-diff-and-log */
  95. + os << " " << i->first
  96. +#else
  97. os << " " << i->first
  98. +#endif
  99. << " to " << i->second << '\n';
  100. }
  101. @@ -228,7 +254,12 @@ static void
  102. }
  103. static void
  104. +#if defined(RSE) /* cosmetics-diff-and-log */
  105. +dump_diffs(app_state & app,
  106. + lua_hooks & lua,
  107. +#else
  108. dump_diffs(lua_hooks & lua,
  109. +#endif
  110. database & db,
  111. cset const & cs,
  112. set<file_path> const & paths,
  113. @@ -238,8 +269,13 @@ dump_diffs(lua_hooks & lua,
  114. bool show_encloser,
  115. bool limit_paths = false)
  116. {
  117. +#if defined(RSE) /* cosmetics-diff-and-log */
  118. + // 67 is somewhat arbitrary (CVS uses this), but less than 80
  119. + string patch_sep = string(67, '=');
  120. +#else
  121. // 60 is somewhat arbitrary, but less than 80
  122. string patch_sep = string(60, '=');
  123. +#endif
  124. for (map<file_path, file_id>::const_iterator
  125. i = cs.files_added.begin();
  126. @@ -248,6 +284,9 @@ dump_diffs(lua_hooks & lua,
  127. if (limit_paths && paths.find(i->first) == paths.end())
  128. continue;
  129. +#if defined(RSE) /* cosmetics-diff-and-log */
  130. + if (!app.opts.no_show_separator)
  131. +#endif
  132. output << patch_sep << '\n';
  133. data unpacked;
  134. vector<string> lines;
  135. @@ -294,6 +333,9 @@ dump_diffs(lua_hooks & lua,
  136. file_data f_old;
  137. data data_old, data_new;
  138. +#if defined(RSE) /* cosmetics-diff-and-log */
  139. + if (!app.opts.no_show_separator)
  140. +#endif
  141. output << patch_sep << '\n';
  142. db.get_file_version(delta_entry_src(i), f_old);
  143. @@ -331,7 +373,12 @@ static void
  144. }
  145. static void
  146. +#if defined(RSE) /* cosmetics-diff-and-log */
  147. +dump_diffs(app_state & app,
  148. + lua_hooks & lua,
  149. +#else
  150. dump_diffs(lua_hooks & lua,
  151. +#endif
  152. database & db,
  153. cset const & cs,
  154. std::ostream & output,
  155. @@ -340,8 +387,13 @@ dump_diffs(lua_hooks & lua,
  156. bool show_encloser)
  157. {
  158. set<file_path> dummy;
  159. +#if defined(RSE) /* cosmetics-diff-and-log */
  160. + dump_diffs(app, lua, db, cs, dummy, output,
  161. + diff_format, new_is_archived, show_encloser);
  162. +#else
  163. dump_diffs(lua, db, cs, dummy, output,
  164. diff_format, new_is_archived, show_encloser);
  165. +#endif
  166. }
  167. // common functionality for diff and automate content_diff to determine
  168. @@ -506,6 +558,9 @@ CMD(diff, "diff", "di", CMD_REF(informat
  169. data summary;
  170. write_cset(included, summary);
  171. +#if defined(RSE) /* cosmetics-diff-and-log */
  172. + if (!app.opts.no_show_header) {
  173. +#endif
  174. vector<string> lines;
  175. split_into_lines(summary(), lines);
  176. cout << "#\n";
  177. @@ -521,6 +576,9 @@ CMD(diff, "diff", "di", CMD_REF(informat
  178. cout << "# " << _("no changes") << '\n';
  179. }
  180. cout << "#\n";
  181. +#if defined(RSE) /* cosmetics-diff-and-log */
  182. + }
  183. +#endif
  184. if (app.opts.diff_format == external_diff)
  185. {
  186. @@ -528,9 +586,15 @@ CMD(diff, "diff", "di", CMD_REF(informat
  187. }
  188. else
  189. {
  190. +#if defined(RSE) /* cosmetics-diff-and-log */
  191. + dump_diffs(app, app.lua, db, included, cout,
  192. + app.opts.diff_format, new_is_archived,
  193. + !app.opts.no_show_encloser);
  194. +#else
  195. dump_diffs(app.lua, db, included, cout,
  196. app.opts.diff_format, new_is_archived,
  197. !app.opts.no_show_encloser);
  198. +#endif
  199. }
  200. }
  201. @@ -558,8 +622,13 @@ CMD_AUTOMATE(content_diff, N_("[FILE [..
  202. prepare_diff(app, db, included, args, new_is_archived, dummy_header);
  203. +#if defined(RSE) /* cosmetics-diff-and-log */
  204. + dump_diffs(app, app.lua, db, included, output,
  205. + app.opts.diff_format, new_is_archived, !app.opts.no_show_encloser);
  206. +#else
  207. dump_diffs(app.lua, db, included, output,
  208. app.opts.diff_format, new_is_archived, !app.opts.no_show_encloser);
  209. +#endif
  210. }
  211. @@ -889,7 +958,11 @@ CMD(log, "log", "", CMD_REF(informative)
  212. else
  213. {
  214. out << string(65, '-') << '\n';
  215. +#if defined(RSE) /* cosmetics-diff-and-log */
  216. + out << "Revision: " << rid << '\n';
  217. +#else
  218. out << "Revision: " << rid << '\n';
  219. +#endif
  220. changes_summary csum;
  221. @@ -904,12 +977,21 @@ CMD(log, "log", "", CMD_REF(informative)
  222. for (set<revision_id>::const_iterator anc = ancestors.begin();
  223. anc != ancestors.end(); ++anc)
  224. +#if defined(RSE) /* cosmetics-diff-and-log */
  225. + out << "Ancestor: " << *anc << '\n';
  226. +
  227. + log_certs(project, out, rid, author_name, "Author: ", false);
  228. + log_certs(project, out, rid, date_name, "Date: ", false);
  229. + log_certs(project, out, rid, branch_name, "Branch: ", false);
  230. + log_certs(project, out, rid, tag_name, "Tag: ", false);
  231. +#else
  232. out << "Ancestor: " << *anc << '\n';
  233. log_certs(project, out, rid, author_name, "Author: ", false);
  234. log_certs(project, out, rid, date_name, "Date: ", false);
  235. log_certs(project, out, rid, branch_name, "Branch: ", false);
  236. log_certs(project, out, rid, tag_name, "Tag: ", false);
  237. +#endif
  238. if (!app.opts.no_files && !csum.cs.empty())
  239. {
  240. @@ -919,16 +1001,26 @@ CMD(log, "log", "", CMD_REF(informative)
  241. }
  242. log_certs(project, out, rid, changelog_name, "ChangeLog: ", true);
  243. +#if defined(RSE) /* cosmetics-diff-and-log */
  244. + log_certs(project, out, rid, comment_name, "Comments: ", true);
  245. +#else
  246. log_certs(project, out, rid, comment_name, "Comments: ", true);
  247. +#endif
  248. }
  249. if (app.opts.diffs)
  250. {
  251. for (edge_map::const_iterator e = rev.edges.begin();
  252. e != rev.edges.end(); ++e)
  253. +#if defined(RSE) /* cosmetics-diff-and-log */
  254. + dump_diffs(app, app.lua, db, edge_changes(e), diff_paths, out,
  255. + app.opts.diff_format, true,
  256. + !app.opts.no_show_encloser, !mask.empty());
  257. +#else
  258. dump_diffs(app.lua, db, edge_changes(e), diff_paths, out,
  259. app.opts.diff_format, true,
  260. !app.opts.no_show_encloser, !mask.empty());
  261. +#endif
  262. }
  263. if (next > 0)
  264. ===================================================================
  265. Index: cmd_netsync.cc
  266. --- cmd_netsync.cc 34174bb7ce83722d7a9859b7065c40243ca0ba75
  267. +++ cmd_netsync.cc 9e4cf97f7d4f031cd68999517822f5fc6121fb82
  268. @@ -253,7 +253,11 @@ CMD(pull, "pull", "", CMD_REF(network),
  269. args, info, false);
  270. if (app.opts.signing_key() == "")
  271. +#if defined(RSE) /* cosmetics-netsync */
  272. + P(F("doing anonymous pull"));
  273. +#else
  274. P(F("doing anonymous pull; use -kKEYNAME if you need authentication"));
  275. +#endif
  276. run_netsync_protocol(app.opts, app.lua, project, keys,
  277. client_voice, sink_role, info);
  278. @@ -356,9 +360,16 @@ CMD(clone, "clone", "", CMD_REF(network)
  279. // paths.cc's idea of the current workspace root is wrong at this point
  280. if (internal_db)
  281. +#if defined(RSE) /* alt-book-keeping-root */
  282. + app.opts.dbname = system_path((directory_exists(workspace_dir / alt_bookkeeping_root_component) ?
  283. + (workspace_dir / alt_bookkeeping_root_component) :
  284. + (workspace_dir / bookkeeping_root_component))
  285. + / ws_internal_db_file_name);
  286. +#else
  287. app.opts.dbname = system_path(workspace_dir
  288. / bookkeeping_root_component
  289. / ws_internal_db_file_name);
  290. +#endif
  291. // this is actually stupid, but app.opts.branchname must be set here
  292. // otherwise it will not be written into _MTN/options, in case
  293. @@ -383,7 +394,11 @@ CMD(clone, "clone", "", CMD_REF(network)
  294. info, true, true, false);
  295. if (app.opts.signing_key() == "")
  296. +#if defined(RSE) /* cosmetics-netsync */
  297. + P(F("doing anonymous pull"));
  298. +#else
  299. P(F("doing anonymous pull; use -kKEYNAME if you need authentication"));
  300. +#endif
  301. // make sure we're back in the original dir so that file: URIs work
  302. change_current_working_dir(start_dir);
  303. ===================================================================
  304. Index: cmd_ws_commit.cc
  305. --- cmd_ws_commit.cc 77b18e38145f345b0eb65b73cc05619464a8fc59
  306. +++ cmd_ws_commit.cc da1133ed41a571f4921798526af49743dc48d0a2
  307. @@ -73,7 +73,14 @@ revision_summary(revision_t const & rev,
  308. for (set<file_path>::const_iterator i = cs.dirs_added.begin();
  309. i != cs.dirs_added.end(); ++i)
  310. +#if defined(RSE) /* cosmetics-stat */
  311. + if ((*i) == file_path())
  312. + out += (F(" added \"\"")).str() += '\n';
  313. + else
  314. + out += (F(" added %s") % *i).str() += '\n';
  315. +#else
  316. out += (F(" added %s") % *i).str() += '\n';
  317. +#endif
  318. for (map<file_path, file_id>::const_iterator i = cs.files_added.begin();
  319. i != cs.files_added.end(); ++i)
  320. @@ -1451,12 +1458,20 @@ CMD_NO_WORKSPACE(import, "import", "", C
  321. catch (...)
  322. {
  323. // clean up before rethrowing
  324. +#if defined(RSE) /* alt-book-keeping-root */
  325. + delete_dir_recursive(directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root);
  326. +#else
  327. delete_dir_recursive(bookkeeping_root);
  328. +#endif
  329. throw;
  330. }
  331. // clean up
  332. +#if defined(RSE) /* alt-book-keeping-root */
  333. + delete_dir_recursive(directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root);
  334. +#else
  335. delete_dir_recursive(bookkeeping_root);
  336. +#endif
  337. }
  338. CMD_NO_WORKSPACE(migrate_workspace, "migrate_workspace", "", CMD_REF(tree),
  339. ===================================================================
  340. Index: diff_patch.cc
  341. --- diff_patch.cc 211424b28fdc3a5dcdae5a781feea97e1e915326
  342. +++ diff_patch.cc 0ebf55f44a911f3e72dc381c1dda3e762103ae7e
  343. @@ -1449,6 +1449,9 @@ make_diff(string const & filename1,
  344. {
  345. case unified_diff:
  346. {
  347. +#if defined(RSE) /* diff-index */
  348. + ost << "Index: " << filename2 << '\n';
  349. +#endif
  350. ost << "--- " << filename1 << '\t'
  351. << id1 << '\n';
  352. ost << "+++ " << filename2 << '\t'
  353. @@ -1460,6 +1463,9 @@ make_diff(string const & filename1,
  354. }
  355. case context_diff:
  356. {
  357. +#if defined(RSE) /* diff-index */
  358. + ost << "Index: " << filename2 << '\n';
  359. +#endif
  360. ost << "*** " << filename1 << '\t'
  361. << id1 << '\n';
  362. ost << "--- " << filename2 << '\t'
  363. ===================================================================
  364. Index: file_io.cc
  365. --- file_io.cc e18d07679c2d210a40f18b67ed0b4b96f5a2c21a
  366. +++ file_io.cc 291d078c4c156479590b4d553810b6a1dff161a3
  367. @@ -397,16 +397,36 @@ write_data(file_path const & path, data
  368. write_data(file_path const & path, data const & dat)
  369. {
  370. // use the bookkeeping root as the temporary directory.
  371. +#if defined(RSE) /* alt-book-keeping-root */
  372. + if (directory_exists(alt_bookkeeping_root)) {
  373. + assert_path_is_directory(alt_bookkeeping_root);
  374. + write_data_impl(path, dat, alt_bookkeeping_root, false);
  375. + }
  376. + else {
  377. +#endif
  378. assert_path_is_directory(bookkeeping_root);
  379. write_data_impl(path, dat, bookkeeping_root, false);
  380. +#if defined(RSE) /* alt-book-keeping-root */
  381. + }
  382. +#endif
  383. }
  384. void
  385. write_data(bookkeeping_path const & path, data const & dat)
  386. {
  387. // use the bookkeeping root as the temporary directory.
  388. +#if defined(RSE) /* alt-book-keeping-root */
  389. + if (directory_exists(alt_bookkeeping_root)) {
  390. + assert_path_is_directory(alt_bookkeeping_root);
  391. + write_data_impl(path, dat, alt_bookkeeping_root, false);
  392. + }
  393. + else {
  394. +#endif
  395. assert_path_is_directory(bookkeeping_root);
  396. write_data_impl(path, dat, bookkeeping_root, false);
  397. +#if defined(RSE) /* alt-book-keeping-root */
  398. + }
  399. +#endif
  400. }
  401. void
  402. ===================================================================
  403. Index: lua_hooks.cc
  404. --- lua_hooks.cc e93b511c04660956edd432fda230877ca3c6fc2b
  405. +++ lua_hooks.cc 0286c7452a45384187df02ccf6e33ee311828372
  406. @@ -209,7 +209,11 @@ lua_hooks::load_rcfiles(options & opts)
  407. {
  408. load_rcfile(opts.conf_dir / "monotonerc", false);
  409. }
  410. +#if defined(RSE) /* alt-book-keeping-root */
  411. + load_rcfile((directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / "monotonerc", false);
  412. +#else
  413. load_rcfile(bookkeeping_root / "monotonerc", false);
  414. +#endif
  415. }
  416. // Command-line rcfiles override even that.
  417. ===================================================================
  418. Index: options_list.hh
  419. --- options_list.hh cd0ff5a0d051b4644c02a5f81ed262a512c65360
  420. +++ options_list.hh 25e39a62d57d8c82427a8deae709826cc2bff4a3
  421. @@ -233,6 +233,24 @@ OPTION(diff_options, no_show_encloser, f
  422. no_show_encloser = true;
  423. }
  424. #endif
  425. +#if defined(RSE) /* cosmetics-diff-and-log */
  426. +OPTVAR(diff_options, bool, no_show_header, false)
  427. +OPTION(diff_options, no_show_header, false, "no-show-header",
  428. + gettext_noop("do not show the summary header"))
  429. +#ifdef option_bodies
  430. +{
  431. + no_show_header = true;
  432. +}
  433. +#endif
  434. +OPTVAR(diff_options, bool, no_show_separator, false)
  435. +OPTION(diff_options, no_show_separator, false, "no-show-separator",
  436. + gettext_noop("do not show the separator line"))
  437. +#ifdef option_bodies
  438. +{
  439. + no_show_separator = true;
  440. +}
  441. +#endif
  442. +#endif
  443. OPT(diffs, "diffs", bool, false, gettext_noop("print diffs along with logs"))
  444. #ifdef option_bodies
  445. ===================================================================
  446. Index: paths.cc
  447. --- paths.cc dde6659e387c8890c96278ea29e3196bdf588139
  448. +++ paths.cc 3101fad7134c9f2383bee0b65219cdec1d46f2e4
  449. @@ -227,7 +227,11 @@ in_bookkeeping_dir(string const & path)
  450. static inline bool
  451. in_bookkeeping_dir(string const & path)
  452. {
  453. +#if defined(RSE) /* alt-book-keeping-root */
  454. + if (path.size() == 0 || (path[0] != '_' && path[0] != '.'))
  455. +#else
  456. if (path.size() == 0 || (path[0] != '_'))
  457. +#endif
  458. return false;
  459. if (path.size() == 1 || (path[1] != 'M' && path[1] != 'm'))
  460. return false;
  461. @@ -929,6 +933,9 @@ find_and_go_to_workspace(string const &
  462. // first look for the current name of the bookkeeping directory.
  463. // if we don't find it, look for it under the old name, so that
  464. // migration has a chance to work.
  465. +#if defined(RSE) /* alt-book-keeping-root */
  466. + if (!find_bookdir(root, alt_bookkeeping_root_component, current, removed))
  467. +#endif
  468. if (!find_bookdir(root, bookkeeping_root_component, current, removed))
  469. if (!find_bookdir(root, old_bookkeeping_root_component, current, removed))
  470. return false;
  471. @@ -1488,7 +1495,11 @@ static void check_bk_normalizes_to(char
  472. static void check_bk_normalizes_to(char const * before, char const * after)
  473. {
  474. +#if defined(RSE) /* alt-book-keeping-root */
  475. + bookkeeping_path bp((directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / before);
  476. +#else
  477. bookkeeping_path bp(bookkeeping_root / before);
  478. +#endif
  479. L(FL("normalizing %s to %s (got %s)") % before % after % bp);
  480. UNIT_TEST_CHECK(bp.as_external() == after);
  481. UNIT_TEST_CHECK(bookkeeping_path(bp.as_internal()).as_internal() == bp.as_internal());
  482. ===================================================================
  483. Index: paths.hh
  484. --- paths.hh 7dd47155b2962d3e4f5fe8764b11c955791803fc
  485. +++ paths.hh d29c84938079b1571cc843c7b7c6c61e420421d7
  486. @@ -328,6 +328,15 @@ private:
  487. // for migration
  488. #define old_bookkeeping_root_component (path_component("MT"))
  489. +#if defined(RSE) /* alt-book-keeping-root */
  490. +#ifndef MTN_ALT_BKROOT
  491. +#define MTN_ALT_BKROOT ".mtn"
  492. +#endif
  493. +#define MTN_ALT_BKROOT_ARG (getenv("MTN_BKROOT") != NULL ? getenv("MTN_BKROOT") : MTN_ALT_BKROOT)
  494. +#define alt_bookkeeping_root (bookkeeping_path(MTN_ALT_BKROOT_ARG))
  495. +#define alt_bookkeeping_root_component (path_component(MTN_ALT_BKROOT_ARG))
  496. +#endif
  497. +
  498. // this will always be an absolute path
  499. class system_path : public any_path
  500. {
  501. ===================================================================
  502. Index: roster_merge.cc
  503. --- roster_merge.cc 9bb39c2c87f92180b0a5db5697ff6ea15b82d25b
  504. +++ roster_merge.cc 9b75d448ee88458f86092ee8d7f4720b24d211a9
  505. @@ -1854,6 +1854,20 @@ roster_merge(roster_t const & left_paren
  506. result.roster.detach_node(n->self);
  507. result.invalid_name_conflicts.push_back(conflict);
  508. }
  509. +#if defined(RSE) /* alt-book-keeping-root */
  510. + if (result_root->has_child(alt_bookkeeping_root_component))
  511. + {
  512. + invalid_name_conflict conflict;
  513. + node_t n = result_root->get_child(alt_bookkeeping_root_component);
  514. + conflict.nid = n->self;
  515. + conflict.parent_name.first = n->parent;
  516. + conflict.parent_name.second = n->name;
  517. + I(n->name == alt_bookkeeping_root_component);
  518. +
  519. + result.roster.detach_node(n->self);
  520. + result.invalid_name_conflicts.push_back(conflict);
  521. + }
  522. +#endif
  523. }
  524. }
  525. @@ -2786,7 +2800,12 @@ struct simple_invalid_name_conflict : pu
  526. I(!result.is_clean());
  527. invalid_name_conflict const & c = idx(result.invalid_name_conflicts, 0);
  528. I(c.nid == bad_dir_nid);
  529. +#if defined(RSE) /* alt-book-keeping-root */
  530. + I( c.parent_name == make_pair(new_root_nid, bookkeeping_root_component)
  531. + || c.parent_name == make_pair(new_root_nid, alt_bookkeeping_root_component));
  532. +#else
  533. I(c.parent_name == make_pair(new_root_nid, bookkeeping_root_component));
  534. +#endif
  535. // this tests it was detached, implicitly
  536. result.roster.attach_node(bad_dir_nid, file_path_internal("dir_formerly_known_as__MTN"));
  537. result.invalid_name_conflicts.pop_back();
  538. ===================================================================
  539. Index: std_hooks.lua
  540. --- std_hooks.lua 7e22137903335a8b7dd2ce7bc9969b8962ff85be
  541. +++ std_hooks.lua 751f8ca2cb91b2ecca05caef00466bd020ce3ca8
  542. @@ -284,6 +284,15 @@ function edit_comment(basetext, user_log
  543. if user_log_message == "" or string.sub(user_log_message, -1) ~= "\n" then
  544. tmp:write("\n")
  545. end
  546. + -- #if defined(RSE) /* dot-mtn-message */
  547. + local template_log_message = read_contents_of_file(".mtn-message", "r")
  548. + if template_log_message ~= nil then
  549. + tmp:write(template_log_message)
  550. + if template_log_message == "" or string.sub(template_log_message, -1) ~= "\n" then
  551. + tmp:write("\n")
  552. + end
  553. + end
  554. + -- #endif
  555. tmp:write(basetext)
  556. io.close(tmp)
  557. @@ -1273,3 +1282,201 @@ end
  558. return push_hook_functions(notifier)
  559. end
  560. end
  561. +
  562. +-- #if defined(RSE) /* extra-command */
  563. +
  564. +-- extra command: "mtn fuse REVISION"
  565. +register_command(
  566. + "fuse", "REVISION",
  567. + "Fuse revision into workspace with conflict markers.",
  568. + "Fuse the specified revision into the current workspace by merging " ..
  569. + "the revision into the workspace while providing inline conflict " ..
  570. + "markers for manually resolving the conflicts in the workspace " ..
  571. + "before comitting the conflicts-resolved workspace as the new " ..
  572. + "merged revision.",
  573. + "command_fuse"
  574. +)
  575. +function command_fuse(revision)
  576. + if revision == nil then
  577. + io.stderr:write("mtn: fuse: ERROR: revision not given\n")
  578. + return
  579. + end
  580. + if program_exists_in_path("mtn") == 0 then
  581. + io.stderr:write("mtn: fuse: ERROR: require Monotone command \"mtn\" in PATH\n")
  582. + return
  583. + end
  584. + mtn_automate("get_option", "branch") -- make sure we have a valid workspace
  585. + local cmd =
  586. + "MTN_MERGE=diffutils " ..
  587. + "MTN_MERGE_DIFFUTILS=\"partial,diff3opts=-E\" " ..
  588. + "mtn " .. "merge_into_workspace " .. revision
  589. + local rc = execute("sh", "-c", cmd)
  590. + if rc ~= 0 then
  591. + io.stderr:write("mtn: fuse: ERROR: failed to execute command \"" .. cmd .. "\"\n")
  592. + end
  593. +end
  594. +
  595. +-- extra command: "mtn conflicts"
  596. +register_command(
  597. + "conflicts", "",
  598. + "Lists files in workspace containing conflict markers.",
  599. + "Lists all files in the current workspace containing the " ..
  600. + "conflict markers produced by GNU diffutils' \"diff3\" " ..
  601. + "command. This indicates still unresolved merge conflicts.",
  602. + "command_conflicts"
  603. +)
  604. +function command_conflicts()
  605. + if program_exists_in_path("egrep") == 0 then
  606. + io.stderr:write("mtn: conflicts: ERROR: require GNU grep command \"egrep\" in PATH\n")
  607. + return
  608. + end
  609. + mtn_automate("get_option", "branch") -- make sure we have a valid workspace
  610. + local rc = execute(
  611. + "egrep",
  612. + "--files-with-matches",
  613. + "--recursive",
  614. + "^(<<<<<<<|=======|>>>>>>>) ",
  615. + "."
  616. + )
  617. +end
  618. +
  619. +-- extra command: "mtn rev[ision] REVISION [ANCESTOR-REVISION]"
  620. +register_command(
  621. + "revision", "REVISION [ANCESTOR-REVISION]",
  622. + "Shows summary information about revision(s)",
  623. + "Shows summary information about a particular revision " ..
  624. + "(or a range of revisions in case an ancestor revision is also specified). " ..
  625. + "This is just a convenience wrapper command around \"mtn log --diffs\".",
  626. + "command_revision"
  627. +)
  628. +alias_command(
  629. + "revision",
  630. + "rev"
  631. +)
  632. +function command_revision(revision, ancestor)
  633. + if revision == nil then
  634. + io.stderr:write("mtn: revision: ERROR: no revision specified\n")
  635. + return
  636. + end
  637. + if ancestor == nil then
  638. + ancestor = revision
  639. + end
  640. + mtn_automate("get_option", "branch") -- make sure we have a valid workspace
  641. + execute("mtn", "log", "--diffs", "--no-graph", "--from", ancestor, "--to", revision)
  642. + if rc ~= 0 then
  643. + io.stderr:write("mtn: revision: ERROR: failed to execute\n")
  644. + end
  645. +end
  646. +
  647. +-- extra command: "mtn base {upgrade|diff}"
  648. +register_command(
  649. + "base", "upgrade|diff",
  650. + "Upgrades or compares current branch against base branch",
  651. + "Upgrade current branch from base branch or compares current " ..
  652. + "branch against base branch. The base branch has to be stored " ..
  653. + "either in the \"mtn:base\" attribute of the root directory " ..
  654. + "or in a \".mtn-base\" file in the root directory.",
  655. + "command_base"
  656. +)
  657. +function command_base(op)
  658. + -- sanity check command line
  659. + if op == nil then
  660. + io.stderr:write("mtn: base: ERROR: no operation specified\n")
  661. + return
  662. + end
  663. + if op ~= "upgrade" and op ~= "diff" then
  664. + io.stderr:write("mtn: base: ERROR: either \"upgrade\" or \"diff\" operation has to be specified\n")
  665. + return
  666. + end
  667. +
  668. + -- determine current branch of workspace
  669. + local branch_this = nil
  670. + local rc, txt = mtn_automate("get_option", "branch")
  671. + if txt ~= nil then
  672. + branch_this = string.match(txt, "^%s*(%S+)%s*$")
  673. + end
  674. + if branch_this == nil then
  675. + io.stderr:write("mtn: base: ERROR: failed to determine current branch\n")
  676. + return
  677. + end
  678. +
  679. + -- determine base branch of workspace
  680. + local branch_base = nil
  681. + local rc, txt = mtn_automate("get_attributes", ".")
  682. + if txt ~= nil then
  683. + branch_base = string.match(txt, "attr%s+\"mtn:base\"%s+\"([^\"]+)\"")
  684. + end
  685. + if branch_base == nil then
  686. + local txt = read_contents_of_file(".mtn-base", "r")
  687. + if txt ~= nil then
  688. + branch_base = string.match(txt, "^%s*(%S+)%s*$")
  689. + end
  690. + end
  691. + if branch_base == nil then
  692. + io.stderr:write("mtn: base: ERROR: failed to determine base branch\n")
  693. + return
  694. + end
  695. +
  696. + -- dispatch according to operation
  697. + if op == "upgrade" then
  698. + -- upgrade current branch by merging in revisions of base branch
  699. + local rc = execute("mtn", "propagate", branch_base, branch_this)
  700. + if rc ~= 0 then
  701. + io.stderr:write("mtn: base: ERROR: failed to execute \"mtn propagate\"\n")
  702. + return
  703. + end
  704. + rc = execute("mtn", "update")
  705. + if rc ~= 0 then
  706. + io.stderr:write("mtn: base: ERROR: failed to execute \"mtn update\"\n")
  707. + return
  708. + end
  709. + elseif op == "diff" then
  710. + -- upgrade current branch by merging in revisions of base branch
  711. + local rc = execute("mtn", "diff", "-r", "h:" .. branch_base, "-r", "h:" .. branch_this)
  712. + if rc ~= 0 then
  713. + io.stderr:write("mtn: base: ERROR: failed to execute \"mtn diff\"\n")
  714. + return
  715. + end
  716. + end
  717. + return
  718. +end
  719. +
  720. +-- extra command: "mtn init"
  721. +register_command(
  722. + "init", "BRANCH",
  723. + "Place local directory under local version control.",
  724. + "Creates a new _MTN/mtn.db database and places the local " ..
  725. + "directory tree under version control using this database.",
  726. + "command_init"
  727. +)
  728. +function command_init(branch)
  729. + -- sanity check command line
  730. + if branch == nil then
  731. + io.stderr:write("mtn: init: ERROR: no branch specified\n")
  732. + return
  733. + end
  734. +
  735. + -- create new database
  736. + execute("mtn", "--db=mtn.db", "db", "init")
  737. +
  738. + -- place current directory under version control
  739. + execute("mtn", "--db=mtn.db", "setup", "-b", branch)
  740. +
  741. + -- use alternative book-keeping directory name
  742. + execute("mv", "_MTN", ".mtn")
  743. +
  744. + -- place database into book-keeping directory
  745. + execute("mv", "mtn.db", ".mtn/mtn.db")
  746. + local txt = read_contents_of_file(".mtn/options")
  747. + txt = string.gsub(txt, "database \"[^\"]*\"", "database \".mtn/mtn.db\"")
  748. + options = io.open(".mtn/options", "w")
  749. + options:write(txt)
  750. + io.close(options)
  751. +
  752. + -- perform a simple operation so that Monotone
  753. + -- updates the book-keeping directory
  754. + execute("sh", "-c", "mtn stat >/dev/null 2>&1")
  755. +end
  756. +
  757. +-- #endif
  758. +
  759. ===================================================================
  760. Index: work.cc
  761. --- work.cc 0ef66673796d2a408587d70530944a5a8747d488
  762. +++ work.cc 8cfa90878704a6fc1553c4dc14bf1be428831674
  763. @@ -57,35 +57,55 @@ get_revision_path(bookkeeping_path & m_p
  764. static void
  765. get_revision_path(bookkeeping_path & m_path)
  766. {
  767. +#if defined(RSE) /* alt-book-keeping-root */
  768. + m_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / revision_file_name;
  769. +#else
  770. m_path = bookkeeping_root / revision_file_name;
  771. +#endif
  772. L(FL("revision path is %s") % m_path);
  773. }
  774. static void
  775. get_options_path(bookkeeping_path & o_path)
  776. {
  777. +#if defined(RSE) /* alt-book-keeping-root */
  778. + o_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / options_file_name;
  779. +#else
  780. o_path = bookkeeping_root / options_file_name;
  781. +#endif
  782. L(FL("options path is %s") % o_path);
  783. }
  784. static void
  785. get_options_path(system_path const & workspace, system_path & o_path)
  786. {
  787. +#if defined(RSE) /* alt-book-keeping-root */
  788. + o_path = (directory_exists(workspace / alt_bookkeeping_root_component) ? (workspace / alt_bookkeeping_root_component) : (workspace / bookkeeping_root_component)) / options_file_name;
  789. +#else
  790. o_path = workspace / bookkeeping_root_component / options_file_name;
  791. +#endif
  792. L(FL("options path is %s") % o_path);
  793. }
  794. static void
  795. get_inodeprints_path(bookkeeping_path & ip_path)
  796. {
  797. +#if defined(RSE) /* alt-book-keeping-root */
  798. + ip_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / inodeprints_file_name;
  799. +#else
  800. ip_path = bookkeeping_root / inodeprints_file_name;
  801. +#endif
  802. L(FL("inodeprints path is %s") % ip_path);
  803. }
  804. static void
  805. get_user_log_path(bookkeeping_path & ul_path)
  806. {
  807. +#if defined(RSE) /* alt-book-keeping-root */
  808. + ul_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / user_log_file_name;
  809. +#else
  810. ul_path = bookkeeping_root / user_log_file_name;
  811. +#endif
  812. L(FL("user log path is %s") % ul_path);
  813. }
  814. @@ -96,7 +116,11 @@ directory_is_workspace(system_path const
  815. {
  816. // as far as the users of this function are concerned, a version 0
  817. // workspace (MT directory instead of _MTN) does not count.
  818. +#if defined(RSE) /* alt-book-keeping-root */
  819. + return (directory_exists(dir / alt_bookkeeping_root_component) || directory_exists(dir / bookkeeping_root_component));
  820. +#else
  821. return directory_exists(dir / bookkeeping_root_component);
  822. +#endif
  823. }
  824. bool workspace::found;
  825. @@ -129,13 +153,24 @@ workspace::create_workspace(options cons
  826. go_to_workspace(new_dir);
  827. mark_std_paths_used();
  828. +#if defined(RSE) /* alt-book-keeping-root */
  829. + N(!(directory_exists(bookkeeping_root) || directory_exists(alt_bookkeeping_root)),
  830. + F("monotone bookkeeping directory '%s' or '%s' already exists in '%s'")
  831. + % bookkeeping_root % alt_bookkeeping_root % new_dir);
  832. +#else
  833. N(!directory_exists(bookkeeping_root),
  834. F("monotone bookkeeping directory '%s' already exists in '%s'")
  835. % bookkeeping_root % new_dir);
  836. +#endif
  837. L(FL("creating bookkeeping directory '%s' for workspace in '%s'")
  838. % bookkeeping_root % new_dir);
  839. +#if defined(RSE) /* alt-book-keeping-root */
  840. + if (getenv("MTN_BKROOT") != NULL)
  841. + mkdir_p(bookkeeping_path(getenv("MTN_BKROOT")));
  842. + else
  843. +#endif
  844. mkdir_p(bookkeeping_root);
  845. workspace::found = true;
  846. @@ -483,9 +518,16 @@ workspace::get_database_option(system_pa
  847. rsa_keypair_id key_option;
  848. system_path keydir_option;
  849. +#if defined(RSE) /* alt-book-keeping-root */
  850. + system_path o_path = (( directory_exists(workspace / alt_bookkeeping_root_component)
  851. + ? (workspace / alt_bookkeeping_root_component)
  852. + : (workspace / bookkeeping_root_component))
  853. + / options_file_name);
  854. +#else
  855. system_path o_path = (workspace
  856. / bookkeeping_root_component
  857. / options_file_name);
  858. +#endif
  859. read_options_file(o_path,
  860. database_option, branch_option, key_option, keydir_option);
  861. }
  862. @@ -563,7 +605,11 @@ workspace::get_local_dump_path(bookkeepi
  863. {
  864. N(workspace::found, F("workspace required but not found"));
  865. +#if defined(RSE) /* alt-book-keeping-root */
  866. + d_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / local_dump_file_name;
  867. +#else
  868. d_path = bookkeeping_root / local_dump_file_name;
  869. +#endif
  870. L(FL("local dump path is %s") % d_path);
  871. }
  872. @@ -976,7 +1022,11 @@ path_for_detached_nids()
  873. static inline bookkeeping_path
  874. path_for_detached_nids()
  875. {
  876. +#if defined(RSE) /* alt-book-keeping-root */
  877. + return (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / "detached";
  878. +#else
  879. return bookkeeping_root / "detached";
  880. +#endif
  881. }
  882. static inline bookkeeping_path
  883. @@ -1715,9 +1765,15 @@ workspace::perform_pivot_root(database &
  884. N(is_dir_t(new_roster.get_node(new_root)),
  885. F("proposed new root directory '%s' is not a directory") % new_root);
  886. {
  887. +#if defined(RSE) /* alt-book-keeping-root */
  888. + N(!(new_roster.has_node(new_root / bookkeeping_root_component) || new_roster.has_node(new_root / alt_bookkeeping_root_component)),
  889. + F("proposed new root directory '%s' contains illegal path %s or %s")
  890. + % new_root % bookkeeping_root % alt_bookkeeping_root);
  891. +#else
  892. N(!new_roster.has_node(new_root / bookkeeping_root_component),
  893. F("proposed new root directory '%s' contains illegal path %s")
  894. % new_root % bookkeeping_root);
  895. +#endif
  896. }
  897. {
  898. ===================================================================
  899. Index: work_migration.cc
  900. --- work_migration.cc 649da47d7b879f1f2814100fdb831b1de7ecaeca
  901. +++ work_migration.cc 21ada50dddc95ba4c9068f89e8db88409c3e2c68
  902. @@ -57,9 +57,18 @@ get_ws_format()
  903. {
  904. unsigned int format;
  905. bookkeeping_path f_path = bookkeeping_root / "format";
  906. +#if defined(RSE) /* alt-book-keeping-root */
  907. + bookkeeping_path alt_f_path = alt_bookkeeping_root / "format";
  908. + if (!file_exists(f_path) && !file_exists(alt_f_path))
  909. +#else
  910. if (!file_exists(f_path))
  911. +#endif
  912. {
  913. +#if defined(RSE) /* alt-book-keeping-root */
  914. + if (directory_exists(bookkeeping_root) || directory_exists(alt_bookkeeping_root))
  915. +#else
  916. if (directory_exists(bookkeeping_root))
  917. +#endif
  918. format = 1;
  919. else if (directory_exists(file_path() / old_bookkeeping_root_component))
  920. format = 0;
  921. @@ -71,7 +80,11 @@ get_ws_format()
  922. data f_dat;
  923. try
  924. {
  925. +#if defined(RSE) /* alt-book-keeping-root */
  926. + read_data(file_exists(alt_f_path) ? alt_f_path : f_path, f_dat);
  927. +#else
  928. read_data(f_path, f_dat);
  929. +#endif
  930. format = lexical_cast<unsigned int>(remove_ws(f_dat()));
  931. }
  932. catch (exception & e)
  933. @@ -82,7 +95,11 @@ get_ws_format()
  934. if (format == 1)
  935. {
  936. W(F("_MTN/format should not exist in a format 1 workspace; corrected"));
  937. +#if defined(RSE) /* alt-book-keeping-root */
  938. + delete_file(file_exists(alt_f_path) ? alt_f_path : f_path);
  939. +#else
  940. delete_file(f_path);
  941. +#endif
  942. }
  943. }
  944. return format;
  945. @@ -92,6 +109,9 @@ workspace::write_ws_format()
  946. workspace::write_ws_format()
  947. {
  948. bookkeeping_path f_path = bookkeeping_root / "format";
  949. +#if defined(RSE) /* alt-book-keeping-root */
  950. + bookkeeping_path alt_f_path = alt_bookkeeping_root / "format";
  951. +#endif
  952. // one or other side of this conditional will always be dead code, but
  953. // both sides should be preserved, to document all historical formats.
  954. // N.B. this will _not_ do the right thing for format 0. Which is fine.
  955. @@ -99,10 +119,19 @@ workspace::write_ws_format()
  956. {
  957. if (file_exists(f_path))
  958. delete_file(f_path);
  959. +#if defined(RSE) /* alt-book-keeping-root */
  960. + if (file_exists(alt_f_path))
  961. + delete_file(alt_f_path);
  962. +#endif
  963. }
  964. else
  965. {
  966. data f_dat(lexical_cast<string>(current_workspace_format) + "\n");
  967. +#if defined(RSE) /* alt-book-keeping-root */
  968. + if (directory_exists(alt_bookkeeping_root))
  969. + write_data(alt_f_path, f_dat);
  970. + else
  971. +#endif
  972. write_data(f_path, f_dat);
  973. }
  974. }
  975. @@ -185,7 +214,11 @@ migrate_1_to_2()
  976. // information, and _MTN/work does not exist; also, there may be more than
  977. // one parent revision, but we do not have to worry about that here.
  978. +#if defined(RSE) /* alt-book-keeping-root */
  979. + bookkeeping_path rev_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / "revision";
  980. +#else
  981. bookkeeping_path rev_path = bookkeeping_root / "revision";
  982. +#endif
  983. data base_rev_data; MM(base_rev_data);
  984. try
  985. {
  986. @@ -201,7 +234,11 @@ migrate_1_to_2()
  987. cset workcs;
  988. MM(workcs);
  989. +#if defined(RSE) /* alt-book-keeping-root */
  990. + bookkeeping_path workcs_path = (directory_exists(alt_bookkeeping_root) ? alt_bookkeeping_root : bookkeeping_root) / "work";
  991. +#else
  992. bookkeeping_path workcs_path = bookkeeping_root / "work";
  993. +#endif
  994. bool delete_workcs = false;
  995. if (file_exists(workcs_path))
  996. {