# # # patch "app_state.cc" # from [907f829b5a05cb08d929ec85b245d5e6e975e027] # to [42d9c8b52697408e2e8c412b43da137fd93e1faf] # # patch "app_state.hh" # from [002842b58181964f749775de1a5f7b3d616de85f] # to [9dace2dc2bb5282d087840c90abaed01ba5406cb] # # patch "automate.cc" # from [d1b854b13c6b3fa0293fdb3c090bcbf88684e071] # to [1098b1b38635b4795ce0b1ab4cf02e29b828a927] # # patch "cmd.hh" # from [443f9905c80e439caf335463cc06061aac0dc641] # to [f0e4d46973929a8c7b70b0e12593de40e7aec203] # # patch "cmd_automate.cc" # from [f49fdacfa01ecb31ad27165784649a34cf343a7b] # to [fdad3e113ea4f077db08c1e789c1f2bf39abe2c0] # # patch "cmd_db.cc" # from [3cc0588377b032c8b436a7145c9c077e91e30227] # to [297c7ba6e5ea74edf822caf8e1acc9b113e5fd66] # # patch "cmd_diff_log.cc" # from [9104b66d0447196da48692151e68cc59f4735b52] # to [1630867b9e3c4004e3f9263e861285dc7f9ad4b1] # # patch "cmd_files.cc" # from [ab72144d225898f3837bf6dc5db576d33639836c] # to [40d4cb0e2464923ab8c9acd08c35cd4f257a520b] # # patch "cmd_key_cert.cc" # from [9608b26014c45b411d49fc018033d63704d50e18] # to [19fe85922f7562f0497f5e5acd6f313d2cfe77f1] # # patch "cmd_list.cc" # from [27e6cda2c9abd8d4756a8604e3026fedda5bf3b3] # to [28bfb5898869212de53955aafe7f90a22c3e909f] # # patch "cmd_merging.cc" # from [fd4090137c7de4255f1f28befebcea19a1a2cf56] # to [3678e7d84993b8c91627cec91a6957e3a3a575c9] # # patch "cmd_netsync.cc" # from [22dba42e1bbf5540eb7de9a918d314c1fbe466eb] # to [c5016fa2f47b78a7507e3845ff42fabf79e01ad1] # # patch "cmd_othervcs.cc" # from [86e381599532f41a2069cf8d6c6a24cfeab0d79b] # to [ef15ac782752f29f76cd018f8fbfb8f79d80fa19] # # patch "cmd_packet.cc" # from [31f9ca76ee6a74da76f3691f64e346ac0d232550] # to [a0706ea1d4cbb5f9531ce639fd0c8003dde21100] # # patch "cmd_ws_commit.cc" # from [0de256cb81117d341fec0f55cb7664d51db95988] # to [616b57df765ad8ec6102a77a0999035e7011c5a0] # # patch "commands.cc" # from [085f80ef9e44e89cf9a8679212f45319f377bda2] # to [16bc6ea6dbf37798359e4cf69e7db609667cf9de] # # patch "key_store.cc" # from [e95db9dc389f17a4c3e57c50c0c5e7aad1799f07] # to [f8de469e5f1ab5743d222be8bf9aea16c76cf3cd] # # patch "monotone.cc" # from [80f8d31167282f20be097b4497456af98e226381] # to [c105422e7de754e19a87af2cd8ad4b798159520e] # # patch "restrictions.cc" # from [30b68aafe5e7549052e8fdf53164264f615a8cae] # to [a61dcdc2f5dc2eef14a0f324de21dfe53a1e1fff] # # patch "restrictions.hh" # from [20265e8afcdb9edc9e070a21e791f4ca7517b968] # to [08cc08dc32191e1f3ec2c44233a09f24d841bacb] # # patch "selectors.cc" # from [c60f8ced9db5d747054b763370746189a7e85874] # to [224c177eb35a210e6ebfd827d236f8300f3cbba0] # # patch "work.cc" # from [3ad67462febf24934ece86c2b7a4ee8417592618] # to [b082863ee52fa26b8a4e208026f63264d2448672] # # patch "work.hh" # from [db1bfaf458523bf0b4400bb90623823421bab433] # to [5811bd0a1000f0e1d30ed8df820bcd3e0bd1ba96] # ============================================================ --- app_state.cc 907f829b5a05cb08d929ec85b245d5e6e975e027 +++ app_state.cc 42d9c8b52697408e2e8c412b43da137fd93e1faf @@ -9,24 +9,14 @@ #include "base.hh" #include "app_state.hh" -#include "sanity.hh" -using std::string; - app_state::app_state() - : lua(this), work(lua), - mtn_automate_allowed(false) + : lua(this), mtn_automate_allowed(false) {} app_state::~app_state() {} -void -app_state::require_workspace() -{ - workspace::require_workspace(opts); -} - // Local Variables: // mode: C++ // fill-column: 76 ============================================================ --- app_state.hh 002842b58181964f749775de1a5f7b3d616de85f +++ app_state.hh 9dace2dc2bb5282d087840c90abaed01ba5406cb @@ -10,16 +10,12 @@ // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. -#include "paths.hh" #include "options.hh" #include "lua_hooks.hh" -#include "work.hh" -// This class is supposed to hold all (or.. well, most) of the state -// of the application, barring some unfortunate static objects like -// the debugging / logging system and the command objects, for the -// time being. The vague intent being to make life easier for anyone -// who wants to embed this program as a library someday. +// This class used to hold most of the state of the application (hence the +// name) but now it's just a wrapper around the options and lua_hooks +// objects, plus one bit of state needed by the Lua extension interfaces. class app_state { @@ -29,11 +25,7 @@ public: options opts; lua_hooks lua; - workspace work; - bool mtn_automate_allowed; - - void require_workspace(); }; // Local Variables: ============================================================ --- automate.cc d1b854b13c6b3fa0293fdb3c090bcbf88684e071 +++ automate.cc 1098b1b38635b4795ce0b1ab4cf02e29b828a927 @@ -39,6 +39,7 @@ #include "globish.hh" #include "charset.hh" #include "safe_map.hh" +#include "work.hh" using std::allocator; using std::basic_ios; @@ -84,7 +85,7 @@ CMD_AUTOMATE(heads, N_("[BRANCH]"), branch = branch_name(idx(args, 0)()); else { - app.require_workspace(); + workspace::require_workspace(F("with no argument, this command prints the heads of the workspace's branch")); branch = app.opts.branchname; } @@ -979,7 +980,7 @@ CMD_AUTOMATE(inventory, N_("[PATH]...") options::opts::no_corresponding_renames) { database db(app); - CMD_REQUIRES_WORKSPACE(app); + workspace work(app); parent_map parents; work.get_parent_rosters(db, parents); @@ -1012,14 +1013,14 @@ CMD_AUTOMATE(inventory, N_("[PATH]...") inserter(excludes, excludes.end())); } - node_restriction nmask(app.work, includes, excludes, app.opts.depth, old_roster, new_roster); + node_restriction nmask(work, includes, excludes, app.opts.depth, old_roster, new_roster); // skip the check of the workspace paths because some of them might // be missing and the user might want to query the recorded structure // of them anyways - path_restriction pmask(app.work, includes, excludes, app.opts.depth, path_restriction::skip_check); + path_restriction pmask(work, includes, excludes, app.opts.depth, path_restriction::skip_check); inventory_rosters(old_roster, new_roster, nmask, pmask, inventory); - inventory_filesystem(app.work, pmask, inventory); + inventory_filesystem(work, pmask, inventory); basic_io::printer pr; @@ -1033,7 +1034,7 @@ CMD_AUTOMATE(inventory, N_("[PATH]...") // check if we should output this element at all // vector states; - inventory_determine_states(app.work, fp, item, + inventory_determine_states(work, fp, item, old_roster, new_roster, states); if (find(states.begin(), states.end(), "ignored") != states.end() && @@ -1198,7 +1199,7 @@ CMD_AUTOMATE(get_revision, N_("[REVID]") if (args.size() == 0) { - CMD_REQUIRES_WORKSPACE(app); + workspace work(app); roster_t new_roster; parent_map old_rosters; @@ -1240,7 +1241,7 @@ CMD_AUTOMATE(get_base_revision_id, "", F("no arguments needed")); database db(app); - CMD_REQUIRES_WORKSPACE(app); + workspace work(app); parent_map parents; work.get_parent_rosters(db, parents); @@ -1267,7 +1268,7 @@ CMD_AUTOMATE(get_current_revision_id, "" N(args.size() == 0, F("no arguments needed")); - CMD_REQUIRES_WORKSPACE(app); + workspace work(app); database db(app); parent_map parents; @@ -1344,7 +1345,7 @@ CMD_AUTOMATE(get_manifest_of, N_("[REVID if (args.size() == 0) { - CMD_REQUIRES_WORKSPACE(app); + workspace work(app); temp_node_id_source nis; @@ -1789,7 +1790,7 @@ CMD_AUTOMATE(get_option, N_("OPTION"), N(args.size() == 1, F("wrong argument count")); - CMD_REQUIRES_WORKSPACE(app); + workspace work(app); work.print_ws_option(args[0], output); } ============================================================ --- cmd.hh 443f9905c80e439caf335463cc06061aac0dc641 +++ cmd.hh f0e4d46973929a8c7b70b0e12593de40e7aec203 @@ -277,10 +277,6 @@ void commands::automate_ ## C :: exec_fr args_vector const & args, \ std::ostream & output) const -#define CMD_REQUIRES_WORKSPACE(app) \ -workspace & work = app.work; \ -app.require_workspace() - CMD_FWD_DECL(__root__); CMD_FWD_DECL(automation); CMD_FWD_DECL(database); ============================================================ --- cmd_automate.cc f49fdacfa01ecb31ad27165784649a34cf343a7b +++ cmd_automate.cc fdad3e113ea4f077db08c1e789c1f2bf39abe2c0 @@ -17,6 +17,7 @@ #include "ui.hh" #include "lua.hh" #include "lua_hooks.hh" +#include "database.hh" using std::istream; using std::make_pair; ============================================================ --- cmd_db.cc 3cc0588377b032c8b436a7145c9c077e91e30227 +++ cmd_db.cc 297c7ba6e5ea74edf822caf8e1acc9b113e5fd66 @@ -19,6 +19,7 @@ #include "project.hh" #include "keys.hh" #include "key_store.hh" +#include "work.hh" using std::cin; using std::cout; @@ -157,8 +158,9 @@ CMD(db_kill_rev_locally, "kill_rev_local // is left out for now if (workspace::found) { + workspace work(app); revision_t old_work_rev; - app.work.get_work_rev(old_work_rev); + work.get_work_rev(old_work_rev); for (edge_map::const_iterator i = old_work_rev.edges.begin(); i != old_work_rev.edges.end(); i++) @@ -166,7 +168,7 @@ CMD(db_kill_rev_locally, "kill_rev_local if (edge_old_revision(i) != revid) continue; - N(!app.work.has_changes(db), + N(!work.has_changes(db), F("Cannot kill revision %s,\n" "because it would leave the current workspace in an invalid\n" "state, from which monotone cannot recover automatically since\n" @@ -180,7 +182,7 @@ CMD(db_kill_rev_locally, "kill_rev_local revision_t new_work_rev; db.get_revision(revid, new_work_rev); new_work_rev.made_for = made_for_workspace; - app.work.put_work_rev(new_work_rev); + work.put_work_rev(new_work_rev); // extra paranoia... we _should_ never run this section twice // since a merged workspace would fail early with work.has_changes() ============================================================ --- cmd_diff_log.cc 9104b66d0447196da48692151e68cc59f4735b52 +++ cmd_diff_log.cc 1630867b9e3c4004e3f9263e861285dc7f9ad4b1 @@ -26,6 +26,7 @@ #include "transforms.hh" #include "app_state.hh" #include "project.hh" +#include "work.hh" using std::cout; using std::deque; @@ -357,11 +358,6 @@ prepare_diff(app_state & app, // initialize before transaction so we have a database to work with. - if (app.opts.revision_selectors.size() == 0) - app.require_workspace(); - else if (app.opts.revision_selectors.size() == 1) - app.require_workspace(); - database db(app); project_t project(db); @@ -373,8 +369,9 @@ prepare_diff(app_state & app, roster_t old_roster, restricted_roster, new_roster; revision_id old_rid; parent_map parents; + workspace work(app); - app.work.get_parent_rosters(db, parents); + work.get_parent_rosters(db, parents); // With no arguments, which parent should we diff against? N(parents.size() == 1, @@ -383,14 +380,14 @@ prepare_diff(app_state & app, old_rid = parent_id(parents.begin()); old_roster = parent_roster(parents.begin()); - app.work.get_current_roster_shape(db, nis, new_roster); + work.get_current_roster_shape(db, nis, new_roster); - node_restriction mask(app.work, args_to_paths(args), + node_restriction mask(work, args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, old_roster, new_roster); - app.work.update_current_roster_from_filesystem(new_roster, mask); + work.update_current_roster_from_filesystem(new_roster, mask); make_restricted_roster(old_roster, new_roster, restricted_roster, mask); @@ -405,18 +402,19 @@ prepare_diff(app_state & app, { roster_t old_roster, restricted_roster, new_roster; revision_id r_old_id; + workspace work(app); complete(app, project, idx(app.opts.revision_selectors, 0)(), r_old_id); db.get_roster(r_old_id, old_roster); - app.work.get_current_roster_shape(db, nis, new_roster); + work.get_current_roster_shape(db, nis, new_roster); - node_restriction mask(app.work, args_to_paths(args), + node_restriction mask(work, args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, old_roster, new_roster); - app.work.update_current_roster_from_filesystem(new_roster, mask); + work.update_current_roster_from_filesystem(new_roster, mask); make_restricted_roster(old_roster, new_roster, restricted_roster, mask); @@ -438,11 +436,6 @@ prepare_diff(app_state & app, db.get_roster(r_old_id, old_roster); db.get_roster(r_new_id, new_roster); - node_restriction mask(app.work, args_to_paths(args), - args_to_paths(app.opts.exclude_patterns), - app.opts.depth, - old_roster, new_roster); - // FIXME: this is *possibly* a UI bug, insofar as we // look at the restriction name(s) you provided on the command // line in the context of new and old, *not* the working copy. @@ -465,6 +458,11 @@ prepare_diff(app_state & app, // (which fails for paths with @'s in them) or possibly //rev/file // since versioned paths are required to be relative. + node_restriction mask(args_to_paths(args), + args_to_paths(app.opts.exclude_patterns), + app.opts.depth, + old_roster, new_roster); + make_restricted_roster(old_roster, new_roster, restricted_roster, mask); @@ -650,11 +648,11 @@ CMD(log, "log", "", CMD_REF(informative) if (app.opts.from.size() == 0) { - workspace::require_workspace(app.opts, - F("try passing a --from revision to start at").str()); + workspace work(app, + F("try passing a --from revision to start at")); revision_t rev; - app.work.get_work_rev(rev); + work.get_work_rev(rev); for (edge_map::const_iterator i = rev.edges.begin(); i != rev.edges.end(); i++) { @@ -689,14 +687,15 @@ CMD(log, "log", "", CMD_REF(informative) // User wants to trace only specific files if (app.opts.from.size() == 0) { + workspace work(app); roster_t new_roster; parent_map parents; temp_node_id_source nis; - app.work.get_parent_rosters(db, parents); - app.work.get_current_roster_shape(db, nis, new_roster); + work.get_parent_rosters(db, parents); + work.get_current_roster_shape(db, nis, new_roster); - mask = node_restriction(app.work, args_to_paths(args), + mask = node_restriction(work, args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, parents, new_roster); } @@ -707,7 +706,7 @@ CMD(log, "log", "", CMD_REF(informative) roster_t roster; db.get_roster(first_rid, roster); - mask = node_restriction(app.work, args_to_paths(args), + mask = node_restriction(args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, roster); } ============================================================ --- cmd_files.cc ab72144d225898f3837bf6dc5db576d33639836c +++ cmd_files.cc 40d4cb0e2464923ab8c9acd08c35cd4f257a520b @@ -20,6 +20,7 @@ #include "transforms.hh" #include "app_state.hh" #include "project.hh" +#include "work.hh" using std::cout; using std::ostream_iterator; @@ -135,9 +136,6 @@ CMD(annotate, "annotate", "", CMD_REF(in database db(app); project_t project(db); - if (app.opts.revision_selectors.size() == 0) - app.require_workspace(); - if ((args.size() != 1) || (app.opts.revision_selectors.size() > 1)) throw usage(execid); @@ -158,9 +156,9 @@ CMD(annotate, "annotate", "", CMD_REF(in // Thus, what we do instead is get the parent rosters, refuse to // proceed if there's more than one, and give do_annotate what it // wants. See tests/two_parent_workspace_annotate. - + workspace work(app); revision_t rev; - app.work.get_work_rev(rev); + work.get_work_rev(rev); N(rev.edges.size() == 1, F("with no revision selected, this command can only be used in " "a single-parent workspace")); @@ -297,10 +295,9 @@ CMD(cat, "cat", "", CMD_REF(informative) revision_id rid; if (app.opts.revision_selectors.size() == 0) { - app.require_workspace(); - + workspace work(app); parent_map parents; - app.work.get_parent_rosters(db, parents); + work.get_parent_rosters(db, parents); N(parents.size() == 1, F("this command can only be used in a single-parent workspace")); rid = parent_id(parents.begin()); @@ -364,7 +361,7 @@ CMD_AUTOMATE(get_file_of, N_("FILENAME") revision_id rid; if (app.opts.revision_selectors.size() == 0) { - CMD_REQUIRES_WORKSPACE(app); + workspace work(app); parent_map parents; work.get_parent_rosters(db, parents); ============================================================ --- cmd_key_cert.cc 9608b26014c45b411d49fc018033d63704d50e18 +++ cmd_key_cert.cc 19fe85922f7562f0497f5e5acd6f313d2cfe77f1 @@ -16,6 +16,7 @@ #include "charset.hh" #include "cmd.hh" #include "app_state.hh" +#include "database.hh" #include "project.hh" #include "keys.hh" #include "key_store.hh" ============================================================ --- cmd_list.cc 27e6cda2c9abd8d4756a8604e3026fedda5bf3b3 +++ cmd_list.cc 28bfb5898869212de53955aafe7f90a22c3e909f @@ -32,6 +32,7 @@ #include "vocab_cast.hh" #include "app_state.hh" #include "project.hh" +#include "work.hh" using std::cout; using std::make_pair; @@ -383,13 +384,13 @@ CMD(known, "known", "", CMD_REF(list), " options::opts::depth | options::opts::exclude) { database db(app); + workspace work(app); + roster_t new_roster; temp_node_id_source nis; + work.get_current_roster_shape(db, nis, new_roster); - app.require_workspace(); - app.work.get_current_roster_shape(db, nis, new_roster); - - node_restriction mask(app.work, args_to_paths(args), + node_restriction mask(work, args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, new_roster); @@ -423,10 +424,10 @@ CMD(unknown, "unknown", "ignored", CMD_R options::opts::depth | options::opts::exclude) { database db(app); - app.require_workspace(); + workspace work(app); vector roots = args_to_paths(args); - path_restriction mask(app.work, roots, args_to_paths(app.opts.exclude_patterns), + path_restriction mask(work, roots, args_to_paths(app.opts.exclude_patterns), app.opts.depth); set unknown, ignored; @@ -434,7 +435,7 @@ CMD(unknown, "unknown", "ignored", CMD_R if (roots.empty()) roots.push_back(file_path()); - app.work.find_unknown_and_ignored(db, mask, roots, unknown, ignored); + work.find_unknown_and_ignored(db, mask, roots, unknown, ignored); utf8 const & realname = execid[execid.size() - 1]; if (realname() == "ignored") @@ -454,16 +455,17 @@ CMD(missing, "missing", "", CMD_REF(list options::opts::depth | options::opts::exclude) { database db(app); + workspace work(app); temp_node_id_source nis; roster_t current_roster_shape; - app.work.get_current_roster_shape(db, nis, current_roster_shape); - node_restriction mask(app.work, args_to_paths(args), + work.get_current_roster_shape(db, nis, current_roster_shape); + node_restriction mask(work, args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, current_roster_shape); set missing; - app.work.find_missing(current_roster_shape, mask, missing); + work.find_missing(current_roster_shape, mask, missing); copy(missing.begin(), missing.end(), ostream_iterator(cout, "\n")); @@ -476,18 +478,17 @@ CMD(changed, "changed", "", CMD_REF(list options::opts::depth | options::opts::exclude) { database db(app); + workspace work(app); + parent_map parents; roster_t new_roster; temp_node_id_source nis; + work.get_current_roster_shape(db, nis, new_roster); + work.update_current_roster_from_filesystem(new_roster); - app.require_workspace(); + work.get_parent_rosters(db, parents); - app.work.get_current_roster_shape(db, nis, new_roster); - app.work.update_current_roster_from_filesystem(new_roster); - - app.work.get_parent_rosters(db, parents); - - node_restriction mask(app.work, args_to_paths(args), + node_restriction mask(work, args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, parents, new_roster); ============================================================ --- cmd_merging.cc fd4090137c7de4255f1f28befebcea19a1a2cf56 +++ cmd_merging.cc 3678e7d84993b8c91627cec91a6957e3a3a575c9 @@ -152,13 +152,13 @@ CMD(update, "update", "", CMD_REF(worksp if (app.opts.revision_selectors.size() > 1) throw usage(execid); - app.require_workspace(); database db(app); + workspace work(app); project_t project(db); // Figure out where we are parent_map parents; - app.work.get_parent_rosters(db, parents); + work.get_parent_rosters(db, parents); N(parents.size() == 1, F("this command can only be used in a single-parent workspace")); @@ -213,7 +213,7 @@ CMD(update, "update", "", CMD_REF(worksp P(F("already up to date at %s") % old_rid); // do still switch the workspace branch, in case they have used // update to switch branches. - app.work.set_ws_options(app.opts, true); + work.set_ws_options(app.opts, true); return; } @@ -253,8 +253,8 @@ CMD(update, "update", "", CMD_REF(worksp shared_ptr working_roster = shared_ptr(new roster_t()); MM(*working_roster); - app.work.get_current_roster_shape(db, nis, *working_roster); - app.work.update_current_roster_from_filesystem(*working_roster); + work.get_current_roster_shape(db, nis, *working_roster); + work.update_current_roster_from_filesystem(*working_roster); revision_t working_rev; revision_id working_rid; @@ -292,17 +292,17 @@ CMD(update, "update", "", CMD_REF(worksp // Now finally modify the workspace cset update; make_cset(*working_roster, merged_roster, update); - app.work.perform_content_update(db, update, wca); + work.perform_content_update(db, update, wca); revision_t remaining; make_revision_for_workspace(chosen_rid, chosen_roster, merged_roster, remaining); // small race condition here... - app.work.put_work_rev(remaining); - app.work.update_any_attrs(db); - app.work.maybe_update_inodeprints(db); - app.work.set_ws_options(app.opts, true); + work.put_work_rev(remaining); + work.update_any_attrs(db); + work.maybe_update_inodeprints(db); + work.set_ws_options(app.opts, true); if (switched_branch) P(F("switched branch; next commit will use branch %s") % app.opts.branchname()); @@ -683,8 +683,8 @@ CMD(merge_into_workspace, "merge_into_wo throw usage(execid); database db(app); + workspace work(app); project_t project(db); - app.require_workspace(); // Get the current state of the workspace. @@ -694,13 +694,13 @@ CMD(merge_into_workspace, "merge_into_wo { parent_map parents; - app.work.get_parent_rosters(db, parents); + work.get_parent_rosters(db, parents); N(parents.size() == 1, F("this command can only be used in a single-parent workspace")); temp_node_id_source nis; - app.work.get_current_roster_shape(db, nis, *working_roster); - app.work.update_current_roster_from_filesystem(*working_roster); + work.get_current_roster_shape(db, nis, *working_roster); + work.update_current_roster_from_filesystem(*working_roster); N(parent_roster(parents.begin()) == *working_roster, F("'%s' can only be used in a workspace with no pending changes") % @@ -763,10 +763,10 @@ CMD(merge_into_workspace, "merge_into_wo make_cset(*left.first, merge_result.roster, update); // small race condition here... - app.work.perform_content_update(db, update, wca); - app.work.put_work_rev(merged_rev); - app.work.update_any_attrs(db); - app.work.maybe_update_inodeprints(db); + work.perform_content_update(db, update, wca); + work.put_work_rev(merged_rev); + work.update_any_attrs(db); + work.maybe_update_inodeprints(db); P(F("updated to result of merge\n" " [left] %s\n" @@ -881,11 +881,12 @@ CMD(pluck, "pluck", "", CMD_REF(workspac "first revision to the second."), options::opts::revision | options::opts::depth | options::opts::exclude) { - // Work out our arguments - revision_id from_rid, to_rid; database db(app); + workspace work(app); project_t project(db); + // Work out our arguments + revision_id from_rid, to_rid; if (app.opts.revision_selectors.size() == 1) { complete(app, project, idx(app.opts.revision_selectors, 0)(), to_rid); @@ -907,8 +908,6 @@ CMD(pluck, "pluck", "", CMD_REF(workspac else throw usage(execid); - app.require_workspace(); - N(!(from_rid == to_rid), F("no changes to apply")); // notionally, we have the situation @@ -948,9 +947,9 @@ CMD(pluck, "pluck", "", CMD_REF(workspac // Get the WORKING roster shared_ptr working_roster = shared_ptr(new roster_t()); MM(*working_roster); - app.work.get_current_roster_shape(db, nis, *working_roster); + work.get_current_roster_shape(db, nis, *working_roster); - app.work.update_current_roster_from_filesystem(*working_roster); + work.update_current_roster_from_filesystem(*working_roster); // Get the FROM->TO cset... cset from_to_to; MM(from_to_to); @@ -958,7 +957,7 @@ CMD(pluck, "pluck", "", CMD_REF(workspac { roster_t to_true_roster; db.get_roster(to_rid, to_true_roster); - node_restriction mask(app.work, args_to_paths(args), + node_restriction mask(work, args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, *from_roster, to_true_roster); @@ -981,7 +980,7 @@ CMD(pluck, "pluck", "", CMD_REF(workspac } parent_map parents; - app.work.get_parent_rosters(db, parents); + work.get_parent_rosters(db, parents); revision_t working_rev; revision_id working_rid; @@ -1021,7 +1020,7 @@ CMD(pluck, "pluck", "", CMD_REF(workspac MM(update); make_cset(*working_roster, merged_roster, update); E(!update.empty(), F("no changes were applied")); - app.work.perform_content_update(db, update, wca); + work.perform_content_update(db, update, wca); P(F("applied changes to workspace")); @@ -1031,13 +1030,13 @@ CMD(pluck, "pluck", "", CMD_REF(workspac make_revision_for_workspace(parents, merged_roster, remaining); // small race condition here... - app.work.put_work_rev(remaining); - app.work.update_any_attrs(db); + work.put_work_rev(remaining); + work.update_any_attrs(db); // add a note to the user log file about what we did { utf8 log; - app.work.read_user_log(log); + work.read_user_log(log); std::string log_str = log(); if (!log_str.empty()) log_str += "\n"; @@ -1049,7 +1048,7 @@ CMD(pluck, "pluck", "", CMD_REF(workspac log_str += (FL("applied partial changes from %s\n" " through %s\n") % from_rid % to_rid).str(); - app.work.write_user_log(utf8(log_str)); + work.write_user_log(utf8(log_str)); } } @@ -1098,10 +1097,10 @@ CMD(get_roster, "get_roster", "", CMD_RE temp_node_id_source nis; revision_id rid(fake_id()); - app.require_workspace(); - app.work.get_parent_rosters(db, parents); - app.work.get_current_roster_shape(db, nis, roster); - app.work.update_current_roster_from_filesystem(roster); + workspace work(app); + work.get_parent_rosters(db, parents); + work.get_current_roster_shape(db, nis, roster); + work.update_current_roster_from_filesystem(roster); if (parents.size() == 0) { ============================================================ --- cmd_netsync.cc 22dba42e1bbf5540eb7de9a918d314c1fbe466eb +++ cmd_netsync.cc c5016fa2f47b78a7507e3845ff42fabf79e01ad1 @@ -14,6 +14,7 @@ #include "platform-wrapped.hh" #include "app_state.hh" #include "project.hh" +#include "work.hh" #include @@ -402,19 +403,20 @@ CMD(clone, "clone", "", CMD_REF(network) L(FL("checking out revision %s to directory %s") % ident % workspace_dir); db.get_roster(ident, current_roster); + workspace work(app); revision_t workrev; make_revision_for_workspace(ident, cset(), workrev); - app.work.put_work_rev(workrev); + work.put_work_rev(workrev); cset checkout; make_cset(*empty_roster, current_roster, checkout); content_merge_checkout_adaptor wca(db); - app.work.perform_content_update(db, checkout, wca, false); + work.perform_content_update(db, checkout, wca, false); - app.work.update_any_attrs(db); - app.work.maybe_update_inodeprints(db); + work.update_any_attrs(db); + work.maybe_update_inodeprints(db); guard.commit(); remove_on_fail.commit(); } ============================================================ --- cmd_othervcs.cc 86e381599532f41a2069cf8d6c6a24cfeab0d79b +++ cmd_othervcs.cc ef15ac782752f29f76cd018f8fbfb8f79d80fa19 @@ -10,6 +10,7 @@ #include "base.hh" #include "cmd.hh" #include "app_state.hh" +#include "database.hh" #include "project.hh" #include "rcs_import.hh" #include "keys.hh" ============================================================ --- cmd_packet.cc 31f9ca76ee6a74da76f3691f64e346ac0d232550 +++ cmd_packet.cc a0706ea1d4cbb5f9531ce639fd0c8003dde21100 @@ -13,6 +13,7 @@ #include "cmd.hh" #include "app_state.hh" +#include "database.hh" #include "key_store.hh" #include "packet.hh" ============================================================ --- cmd_ws_commit.cc 0de256cb81117d341fec0f55cb7664d51db95988 +++ cmd_ws_commit.cc 616b57df765ad8ec6102a77a0999035e7011c5a0 @@ -160,20 +160,20 @@ CMD(revert, "revert", "", CMD_REF(worksp F("you must pass at least one path to 'revert' (perhaps '.')")); database db(app); - app.require_workspace(); + workspace work(app); parent_map parents; - app.work.get_parent_rosters(db, parents); + work.get_parent_rosters(db, parents); N(parents.size() == 1, F("this command can only be used in a single-parent workspace")); old_roster = parent_roster(parents.begin()); { temp_node_id_source nis; - app.work.get_current_roster_shape(db, nis, new_roster); + work.get_current_roster_shape(db, nis, new_roster); } - node_restriction mask(app.work, args_to_paths(args), + node_restriction mask(work, args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, old_roster, new_roster); @@ -185,7 +185,7 @@ CMD(revert, "revert", "", CMD_REF(worksp // specified args and then make a restriction that includes only // these missing files. set missing; - app.work.find_missing(new_roster, mask, missing); + work.find_missing(new_roster, mask, missing); if (missing.empty()) { P(F("no missing files to revert")); @@ -200,7 +200,7 @@ CMD(revert, "revert", "", CMD_REF(worksp missing_files.push_back(*i); } // replace the original mask with a more restricted one - mask = node_restriction(app.work, missing_files, + mask = node_restriction(work, missing_files, std::vector(), app.opts.depth, old_roster, new_roster); } @@ -327,9 +327,9 @@ CMD(revert, "revert", "", CMD_REF(worksp make_revision_for_workspace(parent_id(parents.begin()), preserved, remaining); // Race. - app.work.put_work_rev(remaining); - app.work.update_any_attrs(db); - app.work.maybe_update_inodeprints(db); + work.put_work_rev(remaining); + work.update_any_attrs(db); + work.maybe_update_inodeprints(db); } CMD(disapprove, "disapprove", "", CMD_REF(review), N_("REVISION"), @@ -401,7 +401,7 @@ CMD(mkdir, "mkdir", "", CMD_REF(workspac throw usage(execid); database db(app); - app.require_workspace(); + workspace work(app); set paths; // spin through args and try to ensure that we won't have any collisions @@ -416,7 +416,7 @@ CMD(mkdir, "mkdir", "", CMD_REF(workspac // we'll treat this as a user (fatal) error. it really wouldn't make // sense to add a dir to .mtn-ignore and then try to add it to the // project with a mkdir statement, but one never can tell... - N(app.opts.no_ignore || !app.work.ignore_file(fp), + N(app.opts.no_ignore || !work.ignore_file(fp), F("ignoring directory '%s' [see .mtn-ignore]") % fp); paths.insert(fp); @@ -427,7 +427,7 @@ CMD(mkdir, "mkdir", "", CMD_REF(workspac for (set::const_iterator i = paths.begin(); i != paths.end(); ++i) mkdir_p(*i); - app.work.perform_additions(db, paths, false, !app.opts.no_ignore); + work.perform_additions(db, paths, false, !app.opts.no_ignore); } CMD(add, "add", "", CMD_REF(workspace), N_("[PATH]..."), @@ -440,7 +440,7 @@ CMD(add, "add", "", CMD_REF(workspace), throw usage(execid); database db(app); - app.require_workspace(); + workspace work(app); vector roots = args_to_paths(args); @@ -448,7 +448,7 @@ CMD(add, "add", "", CMD_REF(workspace), bool add_recursive = app.opts.recursive; if (app.opts.unknown) { - path_restriction mask(app.work, roots, + path_restriction mask(work, roots, args_to_paths(app.opts.exclude_patterns), app.opts.depth); set ignored; @@ -457,15 +457,15 @@ CMD(add, "add", "", CMD_REF(workspace), if (roots.empty()) roots.push_back(file_path()); - app.work.find_unknown_and_ignored(db, mask, roots, paths, ignored); + work.find_unknown_and_ignored(db, mask, roots, paths, ignored); - app.work.perform_additions(db, ignored, + work.perform_additions(db, ignored, add_recursive, !app.opts.no_ignore); } else paths = set(roots.begin(), roots.end()); - app.work.perform_additions(db, paths, add_recursive, !app.opts.no_ignore); + work.perform_additions(db, paths, add_recursive, !app.opts.no_ignore); } CMD(drop, "drop", "rm", CMD_REF(workspace), N_("[PATH]..."), @@ -477,19 +477,19 @@ CMD(drop, "drop", "rm", CMD_REF(workspac throw usage(execid); database db(app); - app.require_workspace(); + workspace work(app); set paths; if (app.opts.missing) { temp_node_id_source nis; roster_t current_roster_shape; - app.work.get_current_roster_shape(db, nis, current_roster_shape); - node_restriction mask(app.work, args_to_paths(args), + work.get_current_roster_shape(db, nis, current_roster_shape); + node_restriction mask(work, args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, current_roster_shape); - app.work.find_missing(current_roster_shape, mask, paths); + work.find_missing(current_roster_shape, mask, paths); } else { @@ -497,7 +497,7 @@ CMD(drop, "drop", "rm", CMD_REF(workspac paths = set(roots.begin(), roots.end()); } - app.work.perform_deletions(db, paths, + work.perform_deletions(db, paths, app.opts.recursive, app.opts.bookkeep_only); } @@ -513,7 +513,7 @@ CMD(rename, "rename", "mv", CMD_REF(work throw usage(execid); database db(app); - app.require_workspace(); + workspace work(app); utf8 dstr = args.back(); file_path dst_path = file_path_external(dstr); @@ -533,7 +533,7 @@ CMD(rename, "rename", "mv", CMD_REF(work N(get_path_status(dst_path) == path::directory, F(_("The specified target directory %s/ doesn't exist.")) % dst_path); - app.work.perform_rename(db, src_paths, dst_path, app.opts.bookkeep_only); + work.perform_rename(db, src_paths, dst_path, app.opts.bookkeep_only); } @@ -551,10 +551,10 @@ CMD(pivot_root, "pivot_root", "", CMD_RE throw usage(execid); database db(app); - app.require_workspace(); + workspace work(app); file_path new_root = file_path_external(idx(args, 0)); file_path put_old = file_path_external(idx(args, 1)); - app.work.perform_pivot_root(db, new_root, put_old, + work.perform_pivot_root(db, new_root, put_old, app.opts.bookkeep_only); } @@ -569,16 +569,16 @@ CMD(status, "status", "", CMD_REF(inform temp_node_id_source nis; database db(app); - app.require_workspace(); - app.work.get_parent_rosters(db, old_rosters); - app.work.get_current_roster_shape(db, nis, new_roster); + workspace work(app); + work.get_parent_rosters(db, old_rosters); + work.get_current_roster_shape(db, nis, new_roster); - node_restriction mask(app.work, args_to_paths(args), + node_restriction mask(work, args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, old_rosters, new_roster); - app.work.update_current_roster_from_filesystem(new_roster, mask); + work.update_current_roster_from_filesystem(new_roster, mask); make_restricted_revision(old_rosters, new_roster, mask, rev); utf8 summary; @@ -671,6 +671,7 @@ CMD(checkout, "checkout", "co", CMD_REF( } workspace::create_workspace(app.opts, app.lua, dir); + workspace work(app); shared_ptr empty_roster = shared_ptr(new roster_t()); roster_t current_roster; @@ -680,17 +681,17 @@ CMD(checkout, "checkout", "co", CMD_REF( revision_t workrev; make_revision_for_workspace(revid, cset(), workrev); - app.work.put_work_rev(workrev); + work.put_work_rev(workrev); cset checkout; make_cset(*empty_roster, current_roster, checkout); content_merge_checkout_adaptor wca(db); - app.work.perform_content_update(db, checkout, wca, false); + work.perform_content_update(db, checkout, wca, false); - app.work.update_any_attrs(db); - app.work.maybe_update_inodeprints(db); + work.update_any_attrs(db); + work.maybe_update_inodeprints(db); guard.commit(); } @@ -712,8 +713,8 @@ CMD(attr_drop, "drop", "", CMD_REF(attr) temp_node_id_source nis; database db(app); - app.require_workspace(); - app.work.get_current_roster_shape(db, nis, new_roster); + workspace work(app); + work.get_current_roster_shape(db, nis, new_roster); file_path path = file_path_external(idx(args, 0)); @@ -738,12 +739,12 @@ CMD(attr_drop, "drop", "", CMD_REF(attr) } parent_map parents; - app.work.get_parent_rosters(db, parents); + work.get_parent_rosters(db, parents); revision_t new_work; make_revision_for_workspace(parents, new_roster, new_work); - app.work.put_work_rev(new_work); - app.work.update_any_attrs(db); + work.put_work_rev(new_work); + work.update_any_attrs(db); } CMD(attr_get, "get", "", CMD_REF(attr), N_("PATH [ATTR]"), @@ -760,8 +761,8 @@ CMD(attr_get, "get", "", CMD_REF(attr), temp_node_id_source nis; database db(app); - app.require_workspace(); - app.work.get_current_roster_shape(db, nis, new_roster); + workspace work(app); + work.get_current_roster_shape(db, nis, new_roster); file_path path = file_path_external(idx(args, 0)); @@ -811,8 +812,8 @@ CMD(attr_set, "set", "", CMD_REF(attr), temp_node_id_source nis; database db(app); - app.require_workspace(); - app.work.get_current_roster_shape(db, nis, new_roster); + workspace work(app); + work.get_current_roster_shape(db, nis, new_roster); file_path path = file_path_external(idx(args, 0)); @@ -825,12 +826,12 @@ CMD(attr_set, "set", "", CMD_REF(attr), node->attrs[a_key] = make_pair(true, a_value); parent_map parents; - app.work.get_parent_rosters(db, parents); + work.get_parent_rosters(db, parents); revision_t new_work; make_revision_for_workspace(parents, new_roster, new_work); - app.work.put_work_rev(new_work); - app.work.update_any_attrs(db); + work.put_work_rev(new_work); + work.update_any_attrs(db); } // Name: get_attributes @@ -861,7 +862,7 @@ CMD_AUTOMATE(get_attributes, N_("PATH"), F("wrong argument count")); database db(app); - CMD_REQUIRES_WORKSPACE(app); + workspace work(app); // retrieve the path file_path path = file_path_external(idx(args,0)); @@ -979,7 +980,7 @@ CMD_AUTOMATE(set_attribute, N_("PATH KEY F("wrong argument count")); database db(app); - CMD_REQUIRES_WORKSPACE(app); + workspace work(app); roster_t new_roster; temp_node_id_source nis; @@ -1025,7 +1026,7 @@ CMD_AUTOMATE(drop_attribute, N_("PATH [K F("wrong argument count")); database db(app); - CMD_REQUIRES_WORKSPACE(app); + workspace work(app); roster_t new_roster; temp_node_id_source nis; @@ -1071,6 +1072,7 @@ CMD(commit, "commit", "ci", CMD_REF(work { database db(app); key_store keys(app); + workspace work(app); project_t project(db); utf8 log_message(""); @@ -1081,16 +1083,15 @@ CMD(commit, "commit", "ci", CMD_REF(work temp_node_id_source nis; cset excluded; - app.require_workspace(); - app.work.get_parent_rosters(db, old_rosters); - app.work.get_current_roster_shape(db, nis, new_roster); + work.get_parent_rosters(db, old_rosters); + work.get_current_roster_shape(db, nis, new_roster); - node_restriction mask(app.work, args_to_paths(args), + node_restriction mask(work, args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, old_rosters, new_roster); - app.work.update_current_roster_from_filesystem(new_roster, mask); + work.update_current_roster_from_filesystem(new_roster, mask); make_restricted_revision(old_rosters, new_roster, mask, restricted_rev, excluded, execid); restricted_rev.check_sane(); @@ -1131,7 +1132,7 @@ CMD(commit, "commit", "ci", CMD_REF(work process_commit_message_args(app.opts, log_message_given, log_message); - N(!(log_message_given && app.work.has_contents_user_log()), + N(!(log_message_given && work.has_contents_user_log()), F("_MTN/log is non-empty and log message " "was specified on command line\n" "perhaps move or delete _MTN/log,\n" @@ -1140,7 +1141,7 @@ CMD(commit, "commit", "ci", CMD_REF(work if (!log_message_given) { // This call handles _MTN/log. - get_log_message_interactively(app.lua, app.work, restricted_rev, + get_log_message_interactively(app.lua, work, restricted_rev, app.opts.branchname, log_message); // We only check for empty log messages when the user entered them @@ -1157,7 +1158,7 @@ CMD(commit, "commit", "ci", CMD_REF(work // hit up-arrow to try again, you get an "_MTN/log non-empty and // message given on command line" error... which is annoying. - app.work.write_user_log(log_message); + work.write_user_log(log_message); } // If the hook doesn't exist, allow the message to be used. @@ -1269,7 +1270,7 @@ CMD(commit, "commit", "ci", CMD_REF(work } // the workspace should remember the branch we just committed to. - app.work.set_ws_options(app.opts, true); + work.set_ws_options(app.opts, true); // the work revision is now whatever changes remain on top of the revision // we just checked in. @@ -1277,10 +1278,10 @@ CMD(commit, "commit", "ci", CMD_REF(work make_revision_for_workspace(restricted_rev_id, excluded, remaining); // small race condition here... - app.work.put_work_rev(remaining); + work.put_work_rev(remaining); P(F("committed revision %s") % restricted_rev_id); - app.work.blank_user_log(); + work.blank_user_log(); project.get_branch_heads(app.opts.branchname, heads, app.opts.ignore_suspend_certs); @@ -1290,8 +1291,8 @@ CMD(commit, "commit", "ci", CMD_REF(work % ui.prog_name); } - app.work.update_any_attrs(db); - app.work.maybe_update_inodeprints(db); + work.update_any_attrs(db); + work.maybe_update_inodeprints(db); { // Tell lua what happened. Yes, we might lose some information @@ -1335,10 +1336,11 @@ CMD_NO_WORKSPACE(setup, "setup", "", CMD dir = "."; workspace::create_workspace(app.opts, app.lua, dir); + workspace work(app); revision_t rev; make_revision_for_workspace(revision_id(), cset(), rev); - app.work.put_work_rev(rev); + work.put_work_rev(rev); } CMD_NO_WORKSPACE(import, "import", "", CMD_REF(tree), N_("DIRECTORY"), @@ -1400,12 +1402,13 @@ CMD_NO_WORKSPACE(import, "import", "", C F("import directory '%s' is a file") % dir); workspace::create_workspace(app.opts, app.lua, dir); + workspace work(app); try { revision_t rev; make_revision_for_workspace(ident, cset(), rev); - app.work.put_work_rev(rev); + work.put_work_rev(rev); // prepare stuff for 'add' and so on. args_vector empty_args; @@ -1452,9 +1455,13 @@ CMD_NO_WORKSPACE(migrate_workspace, "mig throw usage(execid); if (args.size() == 1) - go_to_workspace(system_path(idx(args, 0))); + { + go_to_workspace(system_path(idx(args, 0))); + workspace::found = true; + } - app.work.migrate_ws_format(); + workspace work(app, false); + work.migrate_ws_format(); } CMD(refresh_inodeprints, "refresh_inodeprints", "", CMD_REF(tree), "", @@ -1463,9 +1470,9 @@ CMD(refresh_inodeprints, "refresh_inodep options::opts::none) { database db(app); - app.require_workspace(); - app.work.enable_inodeprints(); - app.work.maybe_update_inodeprints(db); + workspace work(app); + work.enable_inodeprints(); + work.maybe_update_inodeprints(db); } ============================================================ --- commands.cc 085f80ef9e44e89cf9a8679212f45319f377bda2 +++ commands.cc 16bc6ea6dbf37798359e4cf69e7db609667cf9de @@ -25,6 +25,7 @@ #include "constants.hh" #include "app_state.hh" #include "project.hh" +#include "work.hh" #ifndef _WIN32 #include "lexical_cast.hh" ============================================================ --- key_store.cc e95db9dc389f17a4c3e57c50c0c5e7aad1799f07 +++ key_store.cc f8de469e5f1ab5743d222be8bf9aea16c76cf3cd @@ -1,9 +1,10 @@ #include "base.hh" #include #include "key_store.hh" #include "file_io.hh" #include "packet.hh" +#include "database.hh" #include "keys.hh" #include "globish.hh" #include "app_state.hh" ============================================================ --- monotone.cc 80f8d31167282f20be097b4497456af98e226381 +++ monotone.cc c105422e7de754e19a87af2cd8ad4b798159520e @@ -31,6 +31,7 @@ #include "sha1.hh" #include "simplestring_xform.hh" #include "platform.hh" +#include "work.hh" using std::cout; ============================================================ --- restrictions.cc 30b68aafe5e7549052e8fdf53164264f615a8cae +++ restrictions.cc a61dcdc2f5dc2eef14a0f324de21dfe53a1e1fff @@ -15,22 +15,11 @@ #include "file_io.hh" #ifdef BUILD_UNIT_TESTS - -#include "unit_tests.hh" -#include "roster.hh" -#include "sanity.hh" -// see comments in restriction.hh -#define WORK_ARGDECL // nothing -#define WORK_ARG // nothing -#define WORK_IGNORE_FILE(f) false - +# include "unit_tests.hh" +# include "roster.hh" +# include "sanity.hh" #else - -#include "work.hh" -#define WORK_ARGDECL workspace & work, -#define WORK_ARG work, -#define WORK_IGNORE_FILE(f) work.ignore_file(f) - +# include "work.hh" #endif using std::make_pair; @@ -72,6 +61,19 @@ static void } static void +map_nodes(map & node_map, + roster_t const & roster, + set const & included_paths, + set const & excluded_paths, + set & known_paths) +{ + map_nodes(node_map, roster, included_paths, known_paths, + restricted_path::included); + map_nodes(node_map, roster, excluded_paths, known_paths, + restricted_path::excluded); +} + +static void map_paths(map & path_map, set const & paths, restricted_path::status const status) @@ -87,79 +89,96 @@ map_paths(map const & included_paths, - set const & excluded_paths, - set const & known_paths) +namespace { - int bad = 0; + struct unknown_p + { + virtual bool operator()(file_path const &) const = 0; + protected: + unknown_p() {} + }; - for (set::const_iterator i = included_paths.begin(); - i != included_paths.end(); ++i) + struct unknown_node : public unknown_p + { + explicit unknown_node(set const & known_paths) + : known_paths(known_paths) + {} + virtual bool operator()(file_path const & p) const { - // ignored paths are allowed into the restriction but are not - // considered invalid if they are found in none of the restriction's - // rosters - if (known_paths.find(*i) == known_paths.end()) - { - if (!WORK_IGNORE_FILE(*i)) - { - bad++; - W(F("restriction includes unknown path '%s'") % *i); - } - } + return known_paths.find(p) == known_paths.end(); } + + private: + set const & known_paths; + }; - for (set::const_iterator i = excluded_paths.begin(); - i != excluded_paths.end(); ++i) + struct unknown_path : public unknown_p + { + virtual bool operator()(file_path const & p) const { - if (known_paths.find(*i) == known_paths.end()) - { - bad++; - W(F("restriction excludes unknown path '%s'") % *i); - } + return !path_exists(p); } + }; - N(bad == 0, FP("%d unknown path", "%d unknown paths", bad) % bad); +#ifndef BUILD_UNIT_TESTS + // ignored paths are allowed into the restriction but are not considered + // invalid if they are found in none of the restriction's rosters + // this is only relevant to the main program, not the unit tests + struct unknown_unignored_node : public unknown_p + { + explicit unknown_unignored_node(set const & known_paths, + workspace & work) + : known_paths(known_paths), work(work) + {} + virtual bool operator()(file_path const & p) const + { + return (known_paths.find(p) == known_paths.end() + && !work.ignore_file(p)); + } + + private: + set const & known_paths; + workspace & work; + }; + + struct unknown_unignored_path : public unknown_p + { + explicit unknown_unignored_path(workspace & work) + : work(work) + {} + virtual bool operator()(file_path const & p) const + { + return !path_exists(p) && !work.ignore_file(p); + } + private: + workspace & work; + }; +#endif } -void -validate_workspace_paths(WORK_ARGDECL - set const & included_paths, - set const & excluded_paths) +static void +validate_paths(set const & included_paths, + set const & excluded_paths, + unknown_p const & is_unknown) { int bad = 0; for (set::const_iterator i = included_paths.begin(); i != included_paths.end(); ++i) - { - if (i->empty()) - continue; + if (is_unknown(*i)) + { + bad++; + W(F("restriction includes unknown path '%s'") % *i); + } - // ignored paths are allowed into the restriction but are not - // considered invalid if they are found in none of the restriction's - // rosters - if (!path_exists(*i) && !WORK_IGNORE_FILE(*i)) - { - bad++; - W(F("restriction includes unknown path '%s'") % *i); - } - } - for (set::const_iterator i = excluded_paths.begin(); i != excluded_paths.end(); ++i) - { - if (i->empty()) - continue; + if (is_unknown(*i)) + { + bad++; + W(F("restriction excludes unknown path '%s'") % *i); + } - if (!path_exists(*i)) - { - bad++; - W(F("restriction excludes unknown path '%s'") % *i); - } - } - N(bad == 0, FP("%d unknown path", "%d unknown paths", bad) % bad); } @@ -171,43 +190,89 @@ restriction::restriction(std::vector const & includes, +node_restriction::node_restriction(std::vector const & includes, std::vector const & excludes, long depth, roster_t const & roster) : restriction(includes, excludes, depth) { - map_nodes(node_map, roster, included_paths, known_paths, - restricted_path::included); - map_nodes(node_map, roster, excluded_paths, known_paths, - restricted_path::excluded); + map_nodes(node_map, roster, included_paths, excluded_paths, known_paths); + validate_paths(included_paths, excluded_paths, unknown_node(known_paths)); +} - validate_roster_paths(WORK_ARG included_paths, excluded_paths, known_paths); +node_restriction::node_restriction(std::vector const & includes, + std::vector const & excludes, + long depth, + roster_t const & roster1, + roster_t const & roster2) : + restriction(includes, excludes, depth) +{ + map_nodes(node_map, roster1, included_paths, excluded_paths, known_paths); + map_nodes(node_map, roster2, included_paths, excluded_paths, known_paths); + validate_paths(included_paths, excluded_paths, unknown_node(known_paths)); } -node_restriction::node_restriction(WORK_ARGDECL +node_restriction::node_restriction(std::vector const & includes, + std::vector const & excludes, + long depth, + parent_map const & rosters1, + roster_t const & roster2) : + restriction(includes, excludes, depth) +{ + for (parent_map::const_iterator i = rosters1.begin(); + i != rosters1.end(); i++) + map_nodes(node_map, parent_roster(i), + included_paths, excluded_paths, known_paths); + map_nodes(node_map, roster2, included_paths, excluded_paths, known_paths); + validate_paths(included_paths, excluded_paths, unknown_node(known_paths)); +} + + +path_restriction::path_restriction(std::vector const & includes, + std::vector const & excludes, + long depth, + validity_check vc) : + restriction(includes, excludes, depth) +{ + map_paths(path_map, included_paths, restricted_path::included); + map_paths(path_map, excluded_paths, restricted_path::excluded); + + if (vc == check_paths) + validate_paths(included_paths, excluded_paths, unknown_path()); +} + +// The constructor variants that take a workspace argument are only used in +// the main program, not the unit tests. Conditional compilation lets us +// leave work.o out of the unit_tester binary. +#ifndef BUILD_UNIT_TESTS +node_restriction::node_restriction(workspace & work, std::vector const & includes, std::vector const & excludes, long depth, + roster_t const & roster) : + restriction(includes, excludes, depth) +{ + map_nodes(node_map, roster, included_paths, excluded_paths, known_paths); + validate_paths(included_paths, excluded_paths, + unknown_unignored_node(known_paths, work)); +} + +node_restriction::node_restriction(workspace & work, + std::vector const & includes, + std::vector const & excludes, + long depth, roster_t const & roster1, roster_t const & roster2) : restriction(includes, excludes, depth) { - map_nodes(node_map, roster1, included_paths, known_paths, - restricted_path::included); - map_nodes(node_map, roster1, excluded_paths, known_paths, - restricted_path::excluded); + map_nodes(node_map, roster1, included_paths, excluded_paths, known_paths); + map_nodes(node_map, roster2, included_paths, excluded_paths, known_paths); - map_nodes(node_map, roster2, included_paths, known_paths, - restricted_path::included); - map_nodes(node_map, roster2, excluded_paths, known_paths, - restricted_path::excluded); - - validate_roster_paths(WORK_ARG included_paths, excluded_paths, known_paths); + validate_paths(included_paths, excluded_paths, + unknown_unignored_node(known_paths, work)); } -node_restriction::node_restriction(WORK_ARGDECL +node_restriction::node_restriction(workspace & work, std::vector const & includes, std::vector const & excludes, long depth, @@ -216,25 +281,16 @@ node_restriction::node_restriction(WORK_ restriction(includes, excludes, depth) { for (parent_map::const_iterator i = rosters1.begin(); - i != rosters1.end(); - i++) - { - map_nodes(node_map, parent_roster(i), included_paths, known_paths, - restricted_path::included); - map_nodes(node_map, parent_roster(i), excluded_paths, known_paths, - restricted_path::excluded); - } - - map_nodes(node_map, roster2, included_paths, known_paths, - restricted_path::included); - map_nodes(node_map, roster2, excluded_paths, known_paths, - restricted_path::excluded); - - validate_roster_paths(WORK_ARG included_paths, excluded_paths, known_paths); + i != rosters1.end(); i++) + map_nodes(node_map, parent_roster(i), + included_paths, excluded_paths, known_paths); + map_nodes(node_map, roster2, included_paths, excluded_paths, known_paths); + validate_paths(included_paths, excluded_paths, + unknown_unignored_node(known_paths, work)); } -path_restriction::path_restriction(WORK_ARGDECL +path_restriction::path_restriction(workspace & work, std::vector const & includes, std::vector const & excludes, long depth, @@ -245,9 +301,12 @@ path_restriction::path_restriction(WORK_ map_paths(path_map, excluded_paths, restricted_path::excluded); if (vc == check_paths) - validate_workspace_paths(WORK_ARG included_paths, excluded_paths); + validate_paths(included_paths, excluded_paths, + unknown_unignored_path(work)); } +#endif + bool node_restriction::includes(roster_t const & roster, node_id nid) const { ============================================================ --- restrictions.hh 20265e8afcdb9edc9e070a21e791f4ca7517b968 +++ restrictions.hh 08cc08dc32191e1f3ec2c44233a09f24d841bacb @@ -72,43 +72,50 @@ class restriction long depth; }; -// When used from the main program, restrictions are always created in a -// context where it's meaningful to provide a workspace object. However, -// restrictions.cc's own unit test harness creates them in a context where -// it is _not_ meaningful to do that. I see no good alternative to this -// little bit of ugliness. - -#ifdef BUILD_UNIT_TESTS -#define WORK_ARGDECL // nothing -#else -#define WORK_ARGDECL workspace & work, // note trailing comma -#endif - class node_restriction : public restriction { public: node_restriction() : restriction() {} - node_restriction(WORK_ARGDECL + node_restriction(std::vector const & includes, + std::vector const & excludes, + long depth, + roster_t const & roster); + + node_restriction(std::vector const & includes, + std::vector const & excludes, + long depth, + roster_t const & roster1, + roster_t const & roster2); + + node_restriction(std::vector const & includes, + std::vector const & excludes, + long depth, + parent_map const & rosters1, + roster_t const & roster2); + +#ifndef BUILD_UNIT_TESTS + node_restriction(workspace & work, std::vector const & includes, std::vector const & excludes, long depth, roster_t const & roster); - node_restriction(WORK_ARGDECL + node_restriction(workspace & work, std::vector const & includes, std::vector const & excludes, long depth, roster_t const & roster1, roster_t const & roster2); - node_restriction(WORK_ARGDECL + node_restriction(workspace & work, std::vector const & includes, std::vector const & excludes, long depth, parent_map const & rosters1, roster_t const & roster2); - +#endif + bool includes(roster_t const & roster, node_id nid) const; node_restriction & operator=(node_restriction const & other) @@ -133,11 +140,18 @@ class path_restriction : public restrict path_restriction() : restriction() {} - path_restriction(WORK_ARGDECL + path_restriction(std::vector const & includes, + std::vector const & excludes, + long depth, + validity_check vc = check_paths); + +#ifndef BUILD_UNIT_TESTS + path_restriction(workspace & work, std::vector const & includes, std::vector const & excludes, long depth, validity_check vc = check_paths); +#endif bool includes(file_path const & sp) const; @@ -145,8 +159,6 @@ class path_restriction : public restrict std::map path_map; }; -#undef WORK_ARGDECL - // Local Variables: // mode: C++ // fill-column: 76 ============================================================ --- selectors.cc c60f8ced9db5d747054b763370746189a7e85874 +++ selectors.cc 224c177eb35a210e6ebfd827d236f8300f3cbba0 @@ -16,6 +16,7 @@ #include "project.hh" #include "globish.hh" #include "cmd.hh" +#include "work.hh" #include #include @@ -153,13 +154,12 @@ decode_selector(app_state & app, case sel_any_head: if (sel.empty()) { - string msg = (sel_branch == type - ? F("the empty branch selector b: refers to " - "the current branch") - : F("the empty head selector h: refers to " - "the head of the current branch") - ).str(); - workspace::require_workspace(app.opts, msg); + i18n_format msg = sel_branch == type + ? F("the empty branch selector b: refers to " + "the current branch") + : F("the empty head selector h: refers to " + "the head of the current branch"); + workspace::require_workspace(msg); sel = app.opts.branchname(); } break; ============================================================ --- work.cc 3ad67462febf24934ece86c2b7a4ee8417592618 +++ work.cc b082863ee52fa26b8a4e208026f63264d2448672 @@ -30,7 +30,7 @@ #include "diff_patch.hh" #include "ui.hh" #include "charset.hh" -#include "lua_hooks.hh" +#include "app_state.hh" using std::deque; using std::exception; @@ -100,13 +100,11 @@ void bool workspace::branch_is_sticky; void -workspace::require_workspace(options const & opts, - string const & explanation) +workspace::require_workspace(i18n_format const & explanation) { + string e = explanation.str(); N(workspace::found, - F("workspace required but not found%s%s") - % (explanation.empty() ? "" : "\n") % explanation); - set_ws_options(opts, false); + F("workspace required but not found%s%s") % (e.empty() ? "" : "\n") % e); } void @@ -155,6 +153,25 @@ workspace::create_workspace(options cons global_sanity.set_dump_path(system_path(dump_path, false).as_external()); } +// Normal-use constructor. +workspace::workspace(app_state & app, bool writeback_options) + : lua(app.lua) +{ + require_workspace(F("")); + if (writeback_options) + set_ws_options(app.opts, false); +} + +workspace::workspace(app_state & app, i18n_format const & explanation, + bool writeback_options) + : lua(app.lua) +{ + require_workspace(explanation); + if (writeback_options) + set_ws_options(app.opts, false); +} + + // routines for manipulating the bookkeeping directory // revision file contains a partial revision describing the workspace ============================================================ --- work.hh db1bfaf458523bf0b4400bb90623823421bab433 +++ work.hh 5811bd0a1000f0e1d30ed8df820bcd3e0bd1ba96 @@ -20,6 +20,7 @@ class lua_hooks; class node_restriction; struct content_merge_adaptor; class lua_hooks; +class i18n_format; // // this file defines structures to deal with the "workspace" of a tree @@ -91,14 +92,24 @@ private: // This is used by get_ws_options and set_ws_options. static bool branch_is_sticky; + // This is used by a lot of instance methods. + lua_hooks & lua; + + // Interfaces. public: - static void require_workspace(options const & opts, - std::string const & explanation = ""); + static void require_workspace(i18n_format const & explanation); static void create_workspace(options const & opts, lua_hooks & lua, system_path const & new_dir); + // Constructor. In normal usage, calling this transitions from the state + // where there may or may not be a workspace to the state where there + // definitely is. + explicit workspace(app_state & app, bool writeback_options = true); + explicit workspace(app_state & app, i18n_format const & explanation, + bool writeback_options = true); + // Methods for manipulating the workspace's content. void find_missing(roster_t const & new_roster_shape, node_restriction const & mask, @@ -230,13 +241,6 @@ public: // that exists, is unknown, and matches one of these regexps is treated as // if it did not exist, instead of being an unknown file. bool ignore_file(file_path const & path); - - // constructor and locals. - workspace(lua_hooks & lua) - : lua(lua) - {} -private: - lua_hooks & lua; }; // Local Variables: