# # # patch "automate.cc" # from [8a1155d54876641573ce3fecba9def947d57cffb] # to [fd30caf826d618d5dccb8b75402c8d48db1a7cca] # # patch "cmd_diff_log.cc" # from [610013ebbe9f839bc9427012fef86b78ad6b48fb] # to [598d52bb8f16c8d44e431d4cbfcdc02cf0f3c5ae] # # patch "cmd_list.cc" # from [74e36aac8b4002f76f096b395c881f25c6388c27] # to [03b36120c182624fc028fdd3303c1affec1876b0] # # patch "cmd_merging.cc" # from [e341d3a8a2fb53bf8a495a484b2c25d902c93519] # to [bd6bb3cad56c7fee89fdf2d1c81ce36bc1546306] # # patch "cmd_ws_commit.cc" # from [68a237875400db79f3e83844acedb021e0958ad9] # to [08e292636ad9de411dc2c8c65cf5a819f49b505d] # # patch "paths.cc" # from [7eb02c15c3c4715e94626ec5f89e5f1b01886e29] # to [ffe8973a49302cc9e5fc2dbf74927dd2c00bf458] # # patch "paths.hh" # from [10edc3da4ba3b6f157a5d03e100ee7dc8bb64346] # to [368ef273f2101d755890c1a9441406c07b1d4157] # # patch "restrictions.cc" # from [21599dba641ccb291d38bd170d79eae5047f924f] # to [4a217d43fdc52b15a744818ecd3cb1b98401d73b] # # patch "restrictions.hh" # from [c64116376fe3f835fe40ca780a8fdde0d900ca91] # to [d5fea25c76c985979abc5e827fde4e6e8cb98e7c] # # patch "work.cc" # from [38fcd998668d9bb8a51f9e3973086a3246c18def] # to [adae88cb01a3e6b39f1f3e593f45ed9c121e66a5] # # patch "work.hh" # from [cd117c8295b2bdf48db35e92aaf29842c27a1b7f] # to [a9f41416559c2d0f44c43aa75b8cf49f2ddc0e05] # ============================================================ --- automate.cc 8a1155d54876641573ce3fecba9def947d57cffb +++ automate.cc fd30caf826d618d5dccb8b75402c8d48db1a7cca @@ -1055,11 +1055,13 @@ CMD_AUTOMATE(inventory, N_("[PATH]...") inserter(excludes, excludes.end())); } - node_restriction nmask(work, includes, excludes, app.opts.depth, old_roster, new_roster); + node_restriction nmask(includes, excludes, app.opts.depth, + old_roster, new_roster, ignored_file(work)); // 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(work, includes, excludes, app.opts.depth, path_restriction::skip_check); + path_restriction pmask(includes, excludes, app.opts.depth, + path_restriction::skip_check); inventory_rosters(old_roster, new_roster, nmask, pmask, inventory); inventory_filesystem(work, pmask, inventory); ============================================================ --- cmd_diff_log.cc 610013ebbe9f839bc9427012fef86b78ad6b48fb +++ cmd_diff_log.cc 598d52bb8f16c8d44e431d4cbfcdc02cf0f3c5ae @@ -385,10 +385,10 @@ prepare_diff(app_state & app, old_roster = parent_roster(parents.begin()); work.get_current_roster_shape(db, nis, new_roster); - node_restriction mask(work, args_to_paths(args), + node_restriction mask(args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, - old_roster, new_roster); + old_roster, new_roster, ignored_file(work)); work.update_current_roster_from_filesystem(new_roster, mask); @@ -412,10 +412,10 @@ prepare_diff(app_state & app, db.get_roster(r_old_id, old_roster); work.get_current_roster_shape(db, nis, new_roster); - node_restriction mask(work, args_to_paths(args), + node_restriction mask(args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, - old_roster, new_roster); + old_roster, new_roster, ignored_file(work)); work.update_current_roster_from_filesystem(new_roster, mask); @@ -714,9 +714,10 @@ CMD(log, "log", "", CMD_REF(informative) work.get_parent_rosters(db, parents); work.get_current_roster_shape(db, nis, new_roster); - mask = node_restriction(work, args_to_paths(args), + mask = node_restriction(args_to_paths(args), args_to_paths(app.opts.exclude_patterns), - app.opts.depth, parents, new_roster); + app.opts.depth, parents, new_roster, + ignored_file(work)); } else { ============================================================ --- cmd_list.cc 74e36aac8b4002f76f096b395c881f25c6388c27 +++ cmd_list.cc 03b36120c182624fc028fdd3303c1affec1876b0 @@ -492,10 +492,10 @@ CMD(known, "known", "", CMD_REF(list), " temp_node_id_source nis; work.get_current_roster_shape(db, nis, new_roster); - node_restriction mask(work, args_to_paths(args), + node_restriction mask(args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, - new_roster); + new_roster, ignored_file(work)); // to be printed sorted vector print_paths; @@ -529,8 +529,8 @@ CMD(unknown, "unknown", "ignored", CMD_R workspace work(app); vector roots = args_to_paths(args); - path_restriction mask(work, roots, args_to_paths(app.opts.exclude_patterns), - app.opts.depth); + path_restriction mask(roots, args_to_paths(app.opts.exclude_patterns), + app.opts.depth, ignored_file(work)); set unknown, ignored; // if no starting paths have been specified use the workspace root @@ -561,10 +561,10 @@ CMD(missing, "missing", "", CMD_REF(list temp_node_id_source nis; roster_t current_roster_shape; work.get_current_roster_shape(db, nis, current_roster_shape); - node_restriction mask(work, args_to_paths(args), + node_restriction mask(args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, - current_roster_shape); + current_roster_shape, ignored_file(work)); set missing; work.find_missing(current_roster_shape, mask, missing); @@ -590,10 +590,10 @@ CMD(changed, "changed", "", CMD_REF(list work.get_parent_rosters(db, parents); - node_restriction mask(work, args_to_paths(args), + node_restriction mask(args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, - parents, new_roster); + parents, new_roster, ignored_file(work)); revision_t rrev; make_restricted_revision(parents, new_roster, mask, rrev); ============================================================ --- cmd_merging.cc e341d3a8a2fb53bf8a495a484b2c25d902c93519 +++ cmd_merging.cc bd6bb3cad56c7fee89fdf2d1c81ce36bc1546306 @@ -1235,10 +1235,11 @@ CMD(pluck, "pluck", "", CMD_REF(workspac { roster_t to_true_roster; db.get_roster(to_rid, to_true_roster); - node_restriction mask(work, args_to_paths(args), + node_restriction mask(args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, - *from_roster, to_true_roster); + *from_roster, to_true_roster, + ignored_file(work)); roster_t restricted_roster; make_restricted_roster(*from_roster, to_true_roster, ============================================================ --- cmd_ws_commit.cc 68a237875400db79f3e83844acedb021e0958ad9 +++ cmd_ws_commit.cc 08e292636ad9de411dc2c8c65cf5a819f49b505d @@ -182,10 +182,10 @@ CMD(revert, "revert", "", CMD_REF(worksp work.get_current_roster_shape(db, nis, new_roster); } - node_restriction mask(work, args_to_paths(args), + node_restriction mask(args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, - old_roster, new_roster); + old_roster, new_roster, ignored_file(work)); if (app.opts.missing) { @@ -209,9 +209,9 @@ CMD(revert, "revert", "", CMD_REF(worksp missing_files.push_back(*i); } // replace the original mask with a more restricted one - mask = node_restriction(work, missing_files, + mask = node_restriction(missing_files, std::vector(), app.opts.depth, - old_roster, new_roster); + old_roster, new_roster, ignored_file(work)); } // We want the restricted roster to include all the changes @@ -463,9 +463,8 @@ CMD(add, "add", "", CMD_REF(workspace), bool add_recursive = app.opts.recursive; if (app.opts.unknown) { - path_restriction mask(work, roots, - args_to_paths(app.opts.exclude_patterns), - app.opts.depth); + path_restriction mask(roots, args_to_paths(app.opts.exclude_patterns), + app.opts.depth, ignored_file(work)); set ignored; // if no starting paths have been specified use the workspace root @@ -500,10 +499,10 @@ CMD(drop, "drop", "rm", CMD_REF(workspac temp_node_id_source nis; roster_t current_roster_shape; work.get_current_roster_shape(db, nis, current_roster_shape); - node_restriction mask(work, args_to_paths(args), + node_restriction mask(args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, - current_roster_shape); + current_roster_shape, ignored_file(work)); work.find_missing(current_roster_shape, mask, paths); } else @@ -588,10 +587,10 @@ CMD(status, "status", "", CMD_REF(inform work.get_parent_rosters(db, old_rosters); work.get_current_roster_shape(db, nis, new_roster); - node_restriction mask(work, args_to_paths(args), + node_restriction mask(args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, - old_rosters, new_roster); + old_rosters, new_roster, ignored_file(work)); work.update_current_roster_from_filesystem(new_roster, mask); make_restricted_revision(old_rosters, new_roster, mask, rev); @@ -1107,10 +1106,10 @@ CMD(commit, "commit", "ci", CMD_REF(work work.get_parent_rosters(db, old_rosters); work.get_current_roster_shape(db, nis, new_roster); - node_restriction mask(work, args_to_paths(args), + node_restriction mask(args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, - old_rosters, new_roster); + old_rosters, new_roster, ignored_file(work)); work.update_current_roster_from_filesystem(new_roster, mask); make_restricted_revision(old_rosters, new_roster, mask, restricted_rev, ============================================================ --- paths.cc 7eb02c15c3c4715e94626ec5f89e5f1b01886e29 +++ paths.cc ffe8973a49302cc9e5fc2dbf74927dd2c00bf458 @@ -829,6 +829,24 @@ system_path::system_path(utf8 const & pa data = const_system_path(utf8(path)); } +// Constant path predicates. +#define IMPLEMENT_CONST_PRED(cls, ret) \ + template <> bool \ + path_always_##ret::operator()(cls const &) const \ + { return ret; } + +IMPLEMENT_CONST_PRED(any_path, false) +IMPLEMENT_CONST_PRED(system_path, false) +IMPLEMENT_CONST_PRED(file_path, false) +IMPLEMENT_CONST_PRED(bookkeeping_path, false) + +IMPLEMENT_CONST_PRED(any_path, true) +IMPLEMENT_CONST_PRED(system_path, true) +IMPLEMENT_CONST_PRED(file_path, true) +IMPLEMENT_CONST_PRED(bookkeeping_path, true) + +#undef IMPLEMENT_CONST_PRED + // If this wasn't a user-supplied path, we should know // which kind it is. boost::shared_ptr ============================================================ --- paths.hh 10edc3da4ba3b6f157a5d03e100ee7dc8bb64346 +++ paths.hh 368ef273f2101d755890c1a9441406c07b1d4157 @@ -102,6 +102,7 @@ // it were a string #include +#include #include "origin_type.hh" class any_path; @@ -396,6 +397,30 @@ template <> void dump(system_path const template <> void dump(bookkeeping_path const & sp, std::string & out); template <> void dump(system_path const & sp, std::string & out); +// Base class for predicate functors on paths. T must be one of the path +// classes. +template +struct path_predicate +{ + BOOST_CLASS_REQUIRE2(T, any_path, boost, ConvertibleConcept); + virtual bool operator()(T const &) const = 0; +protected: + path_predicate() {} + virtual ~path_predicate() {} +}; + +// paths.cc provides always-true and always-false predicates. +template +struct path_always_true : public path_predicate +{ + virtual bool operator()(T const &) const; +}; +template +struct path_always_false : public path_predicate +{ + virtual bool operator()(T const &) const; +}; + // Return a file_path, bookkeeping_path, or system_path, as appropriate. // 'path' is an external path. If to_workspace_root, path is relative to // workspace root, or absolute. Otherwise, it is relative to the current ============================================================ --- restrictions.cc 21599dba641ccb291d38bd170d79eae5047f924f +++ restrictions.cc 4a217d43fdc52b15a744818ecd3cb1b98401d73b @@ -15,13 +15,6 @@ #include "roster.hh" #include "database.hh" // for parent_roster -#ifdef BUILD_UNIT_TESTS -# include "unit_tests.hh" -# include "constants.hh" -#else -# include "work.hh" -#endif - using std::make_pair; using std::map; using std::set; @@ -91,76 +84,42 @@ namespace namespace { - struct unknown_p - { - virtual bool operator()(file_path const &) const = 0; - protected: - unknown_p() {} - virtual ~unknown_p() {} - }; - - 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 - { - return known_paths.find(p) == known_paths.end(); - } - - private: - set const & known_paths; - }; - - struct unknown_path : public unknown_p - { - virtual bool operator()(file_path const & p) const - { - return !path_exists(p); - } - }; - -#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 + struct unknown_unignored_node : public path_predicate { explicit unknown_unignored_node(set const & known_paths, - workspace & work) - : known_paths(known_paths), work(work) + path_predicate const & ignore) + : known_paths(known_paths), ignore_file(ignore) {} virtual bool operator()(file_path const & p) const { - return (known_paths.find(p) == known_paths.end() - && !work.ignore_file(p)); + return (known_paths.find(p) == known_paths.end() && !ignore_file(p)); } private: set const & known_paths; - workspace & work; + path_predicate const & ignore_file; }; - struct unknown_unignored_path : public unknown_p + struct unknown_unignored_path : public path_predicate { - explicit unknown_unignored_path(workspace & work) - : work(work) + explicit unknown_unignored_path(path_predicate const & ignore) + : ignore_file(ignore) {} virtual bool operator()(file_path const & p) const { - return !path_exists(p) && !work.ignore_file(p); + return !path_exists(p) && !ignore_file(p); } private: - workspace & work; + path_predicate const & ignore_file; }; -#endif } static void validate_paths(set const & included_paths, set const & excluded_paths, - unknown_p const & is_unknown) + path_predicate const & is_unknown) { int bad = 0; @@ -195,120 +154,70 @@ node_restriction::node_restriction(std:: node_restriction::node_restriction(std::vector const & includes, std::vector const & excludes, long depth, - roster_t const & roster) : - restriction(includes, excludes, depth) + roster_t const & roster, + path_predicate const & ignore) + : restriction(includes, excludes, depth) { map_nodes(node_map, roster, included_paths, excluded_paths, known_paths); - validate_paths(included_paths, excluded_paths, unknown_node(known_paths)); + validate_paths(included_paths, excluded_paths, + unknown_unignored_node(known_paths, ignore)); } 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) + roster_t const & roster2, + path_predicate const & ignore) + : 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)); + + validate_paths(included_paths, excluded_paths, + unknown_unignored_node(known_paths, ignore)); } 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) + roster_t const & roster2, + path_predicate const & ignore) + : 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)); + validate_paths(included_paths, excluded_paths, + unknown_unignored_node(known_paths, ignore)); } - path_restriction::path_restriction(std::vector const & includes, std::vector const & excludes, long depth, - validity_check vc) : - restriction(includes, excludes, depth) + path_predicate const & ignore) + : 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)); + unknown_unignored_path(ignore)); } -node_restriction::node_restriction(workspace & work, - std::vector const & includes, +path_restriction::path_restriction(std::vector const & includes, std::vector const & excludes, long depth, - roster_t const & roster1, - roster_t const & roster2) : - restriction(includes, excludes, depth) + path_restriction::skip_check_t) + : 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_unignored_node(known_paths, work)); -} - -node_restriction::node_restriction(workspace & work, - 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_unignored_node(known_paths, work)); -} - - -path_restriction::path_restriction(workspace & work, - 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_unignored_path(work)); } -#endif - bool node_restriction::includes(roster_t const & roster, node_id nid) const { @@ -455,6 +364,8 @@ path_restriction::includes(file_path con /////////////////////////////////////////////////////////////////////// #ifdef BUILD_UNIT_TESTS +#include "unit_tests.hh" +#include "constants.hh" using std::string; ============================================================ --- restrictions.hh c64116376fe3f835fe40ca780a8fdde0d900ca91 +++ restrictions.hh d5fea25c76c985979abc5e827fde4e6e8cb98e7c @@ -30,28 +30,26 @@ #include #include "vocab.hh" #include "rev_types.hh" -// XXX needed for gcc 3.3 which will otherwise complain that struct file_path -// is just a forward in rev_types.hh and therefor leads to an incomplete type #include "paths.hh" -class workspace; - // between any two related revisions, A and B, there is a set of changes (a -// cset) that describes the operations required to get from A to B. for example: +// cset) that describes the operations required to get from A to B. for +// example: // // revision A ... changes ... revision B // -// a restriction is a means of masking off some of these changes to produce a -// third revision, X that lies somewhere between A and B. changes included by -// the restriction when applied to revision A would produce revision X. changes -// excluded by the restriction when applied to revision X would produce revision -// B. +// a restriction is a means of masking off some of these changes to produce +// a third revision, X that lies somewhere between A and B. changes +// included by the restriction when applied to revision A would produce +// revision X. changes excluded by the restriction when applied to revision +// X would produce revision B. // -// conceptually, a restriction allows for something like a sliding control for -// selecting the changes between revisions A and B. when the control is "all the -// way to the right" all changes are included and X == B. when then control is -// "all the way to the left" no changes are included and X == A. when the -// control is somewhere between these extremes X is a new revision. +// conceptually, a restriction allows for something like a sliding control +// for selecting the changes between revisions A and B. when the control is +// "all the way to the right" all changes are included and X == B. when then +// control is "all the way to the left" no changes are included and +// X == A. when the control is somewhere between these extremes X is a new +// revision. // // revision A ... included ... revision X ... excluded ... revision B @@ -63,7 +61,8 @@ class restriction class restriction { public: - bool empty() const { return included_paths.empty() && excluded_paths.empty(); } + bool empty() const + { return included_paths.empty() && excluded_paths.empty(); } protected: restriction() : depth(-1) {} @@ -84,42 +83,26 @@ class node_restriction : public restrict node_restriction(std::vector const & includes, std::vector const & excludes, long depth, - roster_t const & roster); + roster_t const & roster, + path_predicate const & ignore_file + = path_always_false()); node_restriction(std::vector const & includes, std::vector const & excludes, long depth, roster_t const & roster1, - roster_t const & roster2); + roster_t const & roster2, + path_predicate const & ignore_file + = path_always_false()); node_restriction(std::vector const & includes, std::vector const & excludes, long depth, parent_map const & rosters1, - roster_t const & roster2); + roster_t const & roster2, + path_predicate const & ignore_file + = path_always_false()); -#ifndef BUILD_UNIT_TESTS - node_restriction(workspace & work, - std::vector const & includes, - std::vector const & excludes, - long depth, - roster_t const & roster); - - node_restriction(workspace & work, - std::vector const & includes, - std::vector const & excludes, - long depth, - roster_t const & roster1, - roster_t const & roster2); - - 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) @@ -140,22 +123,21 @@ class path_restriction : public restrict class path_restriction : public restriction { public: - enum validity_check { check_paths = 0, skip_check }; + enum skip_check_t { skip_check }; path_restriction() : restriction() {} path_restriction(std::vector const & includes, std::vector const & excludes, long depth, - validity_check vc = check_paths); + path_predicate const & ignore_file + = path_always_false()); -#ifndef BUILD_UNIT_TESTS - path_restriction(workspace & work, - std::vector const & includes, + // Skipping validity checks makes the path_predicate irrelevant. + path_restriction(std::vector const & includes, std::vector const & excludes, long depth, - validity_check vc = check_paths); -#endif + skip_check_t); bool includes(file_path const & sp) const; ============================================================ --- work.cc 38fcd998668d9bb8a51f9e3973086a3246c18def +++ work.cc adae88cb01a3e6b39f1f3e593f45ed9c121e66a5 @@ -671,6 +671,12 @@ workspace::ignore_file(file_path const & return lua.hook_ignore_file(path); } +bool +ignored_file::operator()(file_path const & f) const +{ + return work.ignore_file(f); +} + void workspace::init_attributes(file_path const & path, editable_roster_base & er) { ============================================================ --- work.hh cd117c8295b2bdf48db35e92aaf29842c27a1b7f +++ work.hh a9f41416559c2d0f44c43aa75b8cf49f2ddc0e05 @@ -246,6 +246,17 @@ public: bool ignore_file(file_path const & path); }; +// This object turns the workspace ignore_file method into a path predicate, +// suitable for passing to restriction constructors (for instance). +struct ignored_file : public path_predicate +{ + ignored_file(workspace & work) : work(work) {} + bool operator()(file_path const &) const; + +private: + workspace & work; +}; + // Local Variables: // mode: C++ // fill-column: 76