# # # patch "ChangeLog" # from [88305775462778aa644f720ff94a615642a917cf] # to [d7dae52d540e0a14c5efa3f2623a69e762545c5a] # # patch "automate.cc" # from [e94d9b21f86d943fdeed0688b5d151be135454a3] # to [6111b76b19325f315e922506ba45effb8bb67745] # # patch "inodeprint.hh" # from [5038b686d11482660c2f1e2f8d485acdda145670] # to [9b599b89eb011fb1f9b0fc43d095cfe7e5a6a7f7] # # patch "roster.hh" # from [d35f5991b7dbd6741d2281fa0397d9b2136d2288] # to [9865c34aef469e1b07951875a72dcdfa1b117bb9] # # patch "work.cc" # from [95c5685d05ca64884882a7653f75a0bbff65f587] # to [b481a3be180c44adb5868753e2ff121deef7fe2c] # # patch "work.hh" # from [f75890d7970c1c6f41d9956f19d0b22d8882d2e1] # to [6d5b779aa179042965356dfa2b75d8271e9d771a] # ============================================================ --- ChangeLog 88305775462778aa644f720ff94a615642a917cf +++ ChangeLog d7dae52d540e0a14c5efa3f2623a69e762545c5a @@ -1,3 +1,19 @@ +2006-11-18 Derek Scherger + + * automate.cc (struct inventory_itemizer): account for inodeprints + code moving into struct workspace; merge fixups + * inodeprint.hh (inodeprint_file): move declaration above + inodeprint_unchanged which seems to need it + * roster.cc (update_current_roster_from_filesystem): + * work.{cc,hh} (in_inodeprints_mode): + (read_inodeprints): + (write_inodeprints): make these available in struct workspace so + that inventory can use them + (inodeprint_unchanged): removed again; previously moved to + inodeprint.hh; merges seem to keep resurrecting this + (classify_roster_paths): removed again; merges seem to keep + resurrecting this + 2006-11-13 Thomas Moschny * cmd_diff_log.cc (CMD(log)): Fix-ups from last propagate nvm -> ============================================================ --- automate.cc e94d9b21f86d943fdeed0688b5d151be135454a3 +++ automate.cc 6111b76b19325f315e922506ba45effb8bb67745 @@ -620,10 +620,10 @@ struct inventory_itemizer : public tree_ inventory_itemizer(app_state & a, inventory_map & i) : app(a), inventory(i) { - if (in_inodeprints_mode()) + if (app.work.in_inodeprints_mode()) { data dat; - read_inodeprints(dat); + app.work.read_inodeprints(dat); read_inodeprint_map(dat, ipm); } } @@ -722,120 +722,133 @@ AUTOMATE(inventory, "", options::opts::n app.require_workspace(); temp_node_id_source nis; - roster_t base, curr; - inventory_map inventory; - cset cs; MM(cs); - path_set unchanged, changed, missing, unknown, ignored; + roster_t old_roster, new_roster; - app.work.get_base_and_current_roster_shape(base, curr, nis); - make_cset(base, curr, cs); + app.work.get_base_and_current_roster_shape(old_roster, new_roster, nis); - // The current roster (curr) has the complete set of registered nodes - // conveniently with unchanged sha1 hash values. + inventory_map inventory; - // The cset (cs) has the list of drops/renames/adds that have - // occurred between the two rosters along with an empty list of - // deltas. this list is empty only because the current roster used - // to generate the cset does not have current hash values as - // recorded on the filesystem (because get_..._shape was used to - // build it). + inventory_rosters(old_roster, new_roster, inventory); + inventory_filesystem(app, inventory); - path_set nodes_added(cs.dirs_added); - extract_added_file_paths(cs.files_added, nodes_added); + basic_io::printer pr; - inventory_pre_state(inventory, cs.nodes_deleted, - inventory_item::DROPPED_PATH, 0); - inventory_renames(inventory, cs.nodes_renamed); - inventory_post_state(inventory, nodes_added, - inventory_item::ADDED_PATH, 0); - - path_restriction mask; - vector roots; - roots.push_back(file_path()); - - app.work.classify_roster_paths(curr, unchanged, changed, missing); - app.work.find_unknown_and_ignored(mask, roots, unknown, ignored); - - inventory_node_state(inventory, unchanged, - inventory_item::UNCHANGED_NODE); - - inventory_node_state(inventory, changed, - inventory_item::PATCHED_NODE); - - inventory_node_state(inventory, missing, - inventory_item::MISSING_NODE); - - inventory_node_state(inventory, unknown, - inventory_item::UNKNOWN_NODE); - - inventory_node_state(inventory, ignored, - inventory_item::IGNORED_NODE); - - // FIXME: do we want to report on attribute changes here?!? - - for (inventory_map::const_iterator i = inventory.begin(); - i != inventory.end(); ++i) + for (inventory_map::const_iterator i = inventory.begin(); i != inventory.end(); + ++i) { + basic_io::stanza st; + inventory_item const & item = i->second; - string path_suffix; + st.push_file_pair(syms::path, i->first); - if (curr.has_node(i->first)) + if (item.old_node.exists) { - // Explicitly skip the root dir for now. The trailing / dir - // format isn't going to work here. - node_t n = curr.get_node(i->first); - if (is_root_dir_t(n)) continue; - if (is_dir_t(n)) path_suffix = "/"; + string id = lexical_cast(item.old_node.id); +// st.push_str_pair("old_id", lexical_cast(item.old_node.id)); + switch (item.old_node.type) + { + case path::file: st.push_str_triple(syms::old_node, id, "file"); break; + case path::directory: st.push_str_triple(syms::old_node, id, "directory"); break; +// case path::file: st.push_str_pair("old_type", "file"); break; +// case path::directory: st.push_str_pair("old_type", "directory"); break; + case path::nonexistent: I(false); + } } - else if (directory_exists(file_path(i->first))) + + if (item.new_node.exists) { - path_suffix = "/"; + string id = lexical_cast(item.new_node.id); +// st.push_str_pair("new_id", lexical_cast(item.new_node.id)); + switch (item.new_node.type) + { + case path::file: st.push_str_triple(syms::new_node, id, "file"); break; + case path::directory: st.push_str_triple(syms::new_node, id, "directory"); break; +// case path::file: st.push_str_pair("new_type", "file"); break; +// case path::directory: st.push_str_pair("new_type", "directory"); break; + case path::nonexistent: I(false); + } } - switch (i->second.pre_state) + switch (item.fs_type) { - case inventory_item::UNCHANGED_PATH: output << " "; break; - case inventory_item::DROPPED_PATH: output << "D"; break; - case inventory_item::RENAMED_PATH: output << "R"; break; - default: I(false); // invalid pre_state + case path::file: st.push_str_pair(syms::fs_type, "file"); break; + case path::directory: st.push_str_pair(syms::fs_type, "directory"); break; + case path::nonexistent: st.push_str_pair(syms::fs_type, "none"); break; } - switch (i->second.post_state) + if (item.fs_type == path::nonexistent) { - case inventory_item::UNCHANGED_PATH: output << " "; break; - case inventory_item::RENAMED_PATH: output << "R"; break; - case inventory_item::ADDED_PATH: output << "A"; break; - default: I(false); // invalid post_state + if (item.new_node.exists) + st.push_str_pair(syms::status, "missing"); } - - switch (i->second.node_state) + else // exists on filesystem { - case inventory_item::UNCHANGED_NODE: - if (i->second.post_state == inventory_item::ADDED_PATH) - output << "P"; + if (!item.new_node.exists) + { + if (app.lua.hook_ignore_file(i->first)) + st.push_str_pair(syms::status, "ignored"); + else + st.push_str_pair(syms::status, "unknown"); + } + else if (item.new_node.type != item.fs_type) + st.push_str_pair(syms::status, "invalid"); + // TODO: would an ls_invalid command be good for listing these paths? else - output << " "; - break; - case inventory_item::PATCHED_NODE: output << "P"; break; - case inventory_item::UNKNOWN_NODE: output << "U"; break; - case inventory_item::IGNORED_NODE: output << "I"; break; - case inventory_item::MISSING_NODE: output << "M"; break; - default: I(false); // invalid node_state + st.push_str_pair(syms::status, "known"); } - output << " " << i->second.pre_id - << " " << i->second.post_id - << " " << i->first; + // note that we have three sources of information here + // + // the old roster + // the new roster + // the filesystem + // + // the new roster is synthesised from the old roster and the contents of + // _MTN/work and has *not* been updated with content hashes from the + // filesystem. + // + // one path can represent different nodes in the old and new rosters and + // the two different nodes can potentially be different types (file vs dir). + // + // we're interested in comparing the content and attributes of the current + // path in the new roster against their corresponding values in the old + // roster. + // + // the new content hash comes from the filesystem since the new roster has + // not been updated. the new attributes can come directly from the new + // roster. + // + // the old content hash and attributes both come from the old roster but + // we must use the node id of the path in the new roster to get the node + // from the old roster to compare against. - // FIXME: it's possible that a directory was deleted and a file - // was added in it's place (or vice-versa) so we need something - // like pre/post node type indicators rather than a simple path - // suffix! ugh. + if (item.new_node.exists) + { + std::vector changes; - output << path_suffix; + if (item.new_node.type == path::file && old_roster.has_node(item.new_node.id)) + { + file_t old_file = downcast_to_file_t(old_roster.get_node(item.new_node.id)); + old_file->content; + if (item.fs_type == path::file && !(item.fs_ident == old_file->content)) + changes.push_back("content"); + } - output << "\n"; + if (old_roster.has_node(item.new_node.id)) + { + node_t old_node = old_roster.get_node(item.new_node.id); + if (old_node->attrs != item.new_node.attrs) + changes.push_back("attrs"); + } + + if (!changes.empty()) + st.push_str_multi(syms::changes, changes); + } + + pr.print_stanza(st); } + + output.write(pr.buf.data(), pr.buf.size()); } // Name: get_revision ============================================================ --- inodeprint.hh 5038b686d11482660c2f1e2f8d485acdda145670 +++ inodeprint.hh 9b599b89eb011fb1f9b0fc43d095cfe7e5a6a7f7 @@ -31,6 +31,8 @@ void write_inodeprint_map(inodeprint_map void write_inodeprint_map(inodeprint_map const & ipm, data & dat); +bool inodeprint_file(file_path const & file, hexenc & ip); + inline bool inodeprint_unchanged(inodeprint_map const & ipm, file_path const & path) { @@ -48,8 +50,6 @@ inodeprint_unchanged(inodeprint_map cons } -bool inodeprint_file(file_path const & file, hexenc & ip); - // Local Variables: // mode: C++ // fill-column: 76 ============================================================ --- roster.hh d35f5991b7dbd6741d2281fa0397d9b2136d2288 +++ roster.hh 9865c34aef469e1b07951875a72dcdfa1b117bb9 @@ -369,11 +369,6 @@ select_nodes_modified_by_cset(cset const roster_t const & new_roster, std::set & nodes_modified); -void -update_current_roster_from_filesystem(roster_t & ros, -extract_roster_path_set(roster_t const & ros, - path_set & paths); - // These two functions are for the use of things like 'update' or 'pluck', // that need to construct fake rosters and/or markings in-memory, to achieve // particular merge results. ============================================================ --- work.cc 95c5685d05ca64884882a7653f75a0bbff65f587 +++ work.cc b481a3be180c44adb5868753e2ff121deef7fe2c @@ -351,16 +351,16 @@ workspace::get_local_dump_path(bookkeepi // inodeprint file -static bool -in_inodeprints_mode() +bool +workspace::in_inodeprints_mode() { bookkeeping_path ip_path; get_inodeprints_path(ip_path); return file_exists(ip_path); } -static void -read_inodeprints(data & dat) +void +workspace::read_inodeprints(data & dat) { I(in_inodeprints_mode()); bookkeeping_path ip_path; @@ -368,8 +368,8 @@ read_inodeprints(data & dat) read_data(ip_path, dat); } -static void -write_inodeprints(data const & dat) +void +workspace::write_inodeprints(data const & dat) { I(in_inodeprints_mode()); bookkeeping_path ip_path; @@ -841,88 +841,9 @@ add_parent_dirs(split_path const & dst, build.visit_dir(dirname); } -inline static bool -inodeprint_unchanged(inodeprint_map const & ipm, file_path const & path) -{ - inodeprint_map::const_iterator old_ip = ipm.find(path); - if (old_ip != ipm.end()) - { - hexenc ip; - if (inodeprint_file(path, ip) && ip == old_ip->second) - return true; // unchanged - else - return false; // changed or unavailable - } - else - return false; // unavailable -} - // updating rosters from the workspace -// TODO: unchanged, changed, missing might be better as set - -// note that this does not take a restriction because it is used only by -// automate_inventory which operates on the entire, unrestricted, working -// directory. - void -workspace::classify_roster_paths(roster_t const & ros, - path_set & unchanged, - path_set & changed, - path_set & missing) -{ - temp_node_id_source nis; - inodeprint_map ipm; - - if (in_inodeprints_mode()) - { - data dat; - read_inodeprints(dat); - read_inodeprint_map(dat, ipm); - } - - // this code is speed critical, hence the use of inode fingerprints so be - // careful when making changes in here and preferably do some timing tests - - if (!ros.has_root()) - return; - - node_map const & nodes = ros.all_nodes(); - for (node_map::const_iterator i = nodes.begin(); i != nodes.end(); ++i) - { - node_id nid = i->first; - node_t node = i->second; - - split_path sp; - ros.get_name(nid, sp); - - file_path fp(sp); - - if (is_dir_t(node) || inodeprint_unchanged(ipm, fp)) - { - // dirs don't have content changes - unchanged.insert(sp); - } - else - { - file_t file = downcast_to_file_t(node); - file_id fid; - if (ident_existing_file(fp, fid, lua)) - { - if (file->content == fid) - unchanged.insert(sp); - else - changed.insert(sp); - } - else - { - missing.insert(sp); - } - } - } -} - -void workspace::update_current_roster_from_filesystem(roster_t & ros) { update_current_roster_from_filesystem(ros, node_restriction()); ============================================================ --- work.hh f75890d7970c1c6f41d9956f19d0b22d8882d2e1 +++ work.hh 6d5b779aa179042965356dfa2b75d8271e9d771a @@ -193,6 +193,10 @@ struct workspace // the 'inodeprints file' contains inode fingerprints + bool in_inodeprints_mode(); + void read_inodeprints(data & dat); + void write_inodeprints(data const & dat); + void enable_inodeprints(); void maybe_update_inodeprints();