# # patch "commands.cc" # from [9aef810bede9b14d5422b3e41617e985e69ac9df] # to [7901ddd02eeea823a941aab020fc84af450debab] # # patch "roster.cc" # from [5cd0388d9cac4bdfefbc73272833fa5a14c3dea9] # to [f93fa0acd8d00425ab90242c1fa9ab4496d0ac97] # # patch "tests/t_attributes.at" # from [f9a21f085de7224b35dd7df5c1ea1ce8ae6746c2] # to [0ab87a6eb23ea92b166619c30fae7f0bca7c7cd1] # # patch "work.cc" # from [a1e990002ae2c02ec68eb8496dbfb8cb08be73ef] # to [4a3e8be8a554563d87b4bbd0a76a706500e20232] # ======================================================================== --- commands.cc 9aef810bede9b14d5422b3e41617e985e69ac9df +++ commands.cc 7901ddd02eeea823a941aab020fc84af450debab @@ -2158,110 +2158,97 @@ throw usage(name); } -/* -// FIXME_ROSTERS: disabled until rewritten to use rosters -CMD(attr, N_("working copy"), N_("set FILE ATTR VALUE\nget FILE [ATTR]\ndrop FILE"), +CMD(attr, N_("working copy"), N_("set PATH ATTR VALUE\nget PATH [ATTR]\ndrop PATH [ATTR]"), N_("set, get or drop file attributes"), OPT_NONE) { if (args.size() < 2 || args.size() > 4) throw usage(name); - app.require_working_copy(); + revision_set rs; + roster_t old_roster, new_roster; - data attr_data; - file_path attr_path; - attr_map attrs; - get_attr_path(attr_path); - - if (file_exists(attr_path)) - { - read_data(attr_path, attr_data); - read_attr_map(attr_data, attrs); - } + app.require_working_copy(); + get_unrestricted_working_revision_and_rosters(app, rs, old_roster, new_roster); file_path path = file_path_external(idx(args,1)); - N(file_exists(path), F("no such file '%s'") % path); + split_path sp; + path.split(sp); - bool attrs_modified = false; + N(new_roster.has_node(sp), F("Unknown path '%s'") % path); + node_t node = new_roster.get_node(sp); - if (idx(args, 0)() == "set") + string subcmd = idx(args, 0)(); + if (subcmd == "set" || subcmd == "drop") { - if (args.size() != 4) - throw usage(name); - attrs[path][idx(args, 2)()] = idx(args, 3)(); + if (subcmd == "set") + { + if (args.size() != 4) + throw usage(name); - attrs_modified = true; + attr_key a_key = idx(args, 2)(); + attr_value a_value = idx(args, 3)(); + + node->attrs[a_key] = make_pair(true, a_value); + } + else + { + // Clear all attrs (or a specific attr) + if (args.size() == 2) + { + for (full_attr_map_t::iterator i = node->attrs.begin(); + i != node->attrs.end(); ++i) + i->second = make_pair(false, ""); + } + else if (args.size() == 3) + { + attr_key a_key = idx(args, 2)(); + N(node->attrs.find(a_key) != node->attrs.end(), + F("Path '%s' does not have attribute '%s'\n") + % path % a_key); + node->attrs[a_key] = make_pair(false, ""); + } + else + throw usage(name); + } + + cset new_work; + make_cset(old_roster, new_roster, new_work); + put_work_cset(new_work); + update_any_attrs(app); } - else if (idx(args, 0)() == "drop") + else if (subcmd == "get") { if (args.size() == 2) { - attrs.erase(path); + bool has_any_live_attrs = false; + for (full_attr_map_t::const_iterator i = node->attrs.begin(); + i != node->attrs.end(); ++i) + if (i->second.first) + { + cout << path << " : " << i->first << "=" << i->second.second << endl; + has_any_live_attrs = true; + } + if (!has_any_live_attrs) + cout << "No attributes for " << path << endl; } else if (args.size() == 3) { - attrs[path].erase(idx(args, 2)()); + attr_key a_key = idx(args, 2)(); + full_attr_map_t::const_iterator i = node->attrs.find(a_key); + if (i != node->attrs.end() && i->second.first) + cout << path << " : " << i->first << "=" << i->second.second << endl; + else + cout << "No attribute " << a_key << " on path " << path << endl; } else throw usage(name); - - attrs_modified = true; } - else if (idx(args, 0)() == "get") - { - if (args.size() != 2 && args.size() != 3) - throw usage(name); - - attr_map::const_iterator i = attrs.find(path); - if (i == attrs.end()) - cout << "no attributes for " << path << endl; - else - { - if (args.size() == 2) - { - for (std::map::const_iterator j = i->second.begin(); - j != i->second.end(); ++j) - cout << path << " : " << j->first << "=" << j->second << endl; - } - else - { - std::map::const_iterator j = i->second.find(idx(args, 2)()); - if (j == i->second.end()) - cout << "no attribute " << idx(args, 2)() << " on file " << path << endl; - else - cout << path << " : " << j->first << "=" << j->second << endl; - } - } - } else throw usage(name); +} - if (attrs_modified) - { - write_attr_map(attr_data, attrs); - write_data(attr_path, attr_data); - { - // check to make sure .mt-attr exists in - // current manifest. - manifest_map man; - get_base_manifest(app, man); - if (man.find(attr_path) == man.end()) - { - P(F("registering %s file in working copy\n") % attr_path); - change_set::path_rearrangement work; - get_path_rearrangement(work); - vector paths; - paths.push_back(attr_path); - build_additions(paths, man, app, work); - put_path_rearrangement(work); - } - } - } -} -*/ - CMD(commit, N_("working copy"), N_("[PATH]..."), N_("commit working copy to database"), OPT_BRANCH_NAME % OPT_MESSAGE % OPT_MSGFILE % OPT_DATE % ======================================================================== --- roster.cc 5cd0388d9cac4bdfefbc73272833fa5a14c3dea9 +++ roster.cc f93fa0acd8d00425ab90242c1fa9ab4496d0ac97 @@ -1642,6 +1642,15 @@ make_pair(make_pair(to_sp, i.right_key()), i.right_data().second)); } + else if (i.state() == parallel::in_both + && i.right_data().first + && i.left_data().first + && i.right_data().second != i.left_data().second) + { + safe_insert(cs.attrs_set, + make_pair(make_pair(to_sp, i.right_key()), + i.right_data().second)); + } } } } ======================================================================== --- tests/t_attributes.at f9a21f085de7224b35dd7df5c1ea1ce8ae6746c2 +++ tests/t_attributes.at 0ab87a6eb23ea92b166619c30fae7f0bca7c7cd1 @@ -9,23 +9,16 @@ # Check a single character filename too, because those have had bugs. AT_DATA(a, [some data ]) -AT_DATA(.mt-attrs, -[file "foo" - test_attr "true" - file "a" - test_attr "1" -]) - AT_CHECK(MONOTONE add foo, [], [ignore], [ignore]) -AT_CHECK(MONOTONE add .mt-attrs, [], [ignore], [ignore]) +AT_CHECK(MONOTONE add a, [], [ignore], [ignore]) +AT_CHECK(MONOTONE attr set foo test_attr true, [], [ignore], [ignore]) +AT_CHECK(MONOTONE attr set a test_attr 1, [], [ignore], [ignore]) AT_CHECK(MONOTONE --branch=testbranch commit --message=blah-blah, [], [ignore], [ignore]) CO_R_SHA1=`BASE_REVISION` -AT_DATA(.mt-attrs, [ -file "a" -test_attr "2" -]) +AT_CHECK(MONOTONE attr drop foo test_attr, [], [ignore], [ignore]) +AT_CHECK(MONOTONE attr set a test_attr 2, [], [ignore], [ignore]) AT_CHECK(MONOTONE --branch=testbranch commit --message=blah-blah, [], [ignore], [ignore]) UPDATE_R_SHA1=`BASE_REVISION` ======================================================================== --- work.cc a1e990002ae2c02ec68eb8496dbfb8cb08be73ef +++ work.cc 4a3e8be8a554563d87b4bbd0a76a706500e20232 @@ -668,18 +668,6 @@ } -static void -apply_attributes(app_state & app, attr_map const & attr) -{ - for (attr_map::const_iterator i = attr.begin(); - i != attr.end(); ++i) - for (std::map::const_iterator j = i->second.begin(); - j != i->second.end(); ++j) - app.lua.hook_apply_attribute (j->first, - i->first, - j->second); -} - string const encoding_attribute("encoding"); string const binary_encoding("binary"); string const default_encoding("default"); @@ -770,20 +758,27 @@ void update_any_attrs(app_state & app) { -/* -// FIXME_ROSTERS: disabled until rewritten to use rosters - file_path fp; - data attr_data; - attr_map attr; - - get_attr_path(fp); - if (!file_exists(fp)) - return; - - read_data(fp, attr_data); - read_attr_map(attr_data, attr); - apply_attributes(app, attr); -*/ + temp_node_id_source nis; + roster_t new_roster; + get_current_roster_shape(new_roster, nis, app); + node_map const & nodes = new_roster.all_nodes(); + for (node_map::const_iterator i = nodes.begin(); + i != nodes.end(); ++i) + { + node_t n = i->second; + for (full_attr_map_t::const_iterator j = n->attrs.begin(); + j != n->attrs.end(); ++j) + { + if (j->second.first) + { + split_path sp; + new_roster.get_name(i->first, sp); + app.lua.hook_apply_attribute (j->first(), + file_path(sp), + j->second.second()); + } + } + } } editable_working_tree::editable_working_tree(app_state & app,