# # # patch "cmd_list.cc" # from [4484b5f175f144ffe3f505686eebf169941db916] # to [17438456f9456eeeac4965cdb0f91878daeec4fe] # # patch "database.cc" # from [a4a8ac204d750aa31eb5a45196ed6ba770e626f9] # to [d061178f713d11eaeb8258766a0652829ab56f6a] # # patch "database.hh" # from [8a1debf42e1ccc4263c755cb2c12b6a683dd563c] # to [c60049b83091daa228f0f05487bb5d09218c14e3] # # patch "lua_hooks.cc" # from [24acf3a1517806ad897f64f2787381d5ececd47f] # to [01bab6def621315198c957c066e3485417ffafc7] # # patch "work.cc" # from [939366f93f579840c44ed3979057f7a00bd92b07] # to [8e9f5b11f99b845d327d237f1f542ebe72ab0e63] # ============================================================ --- cmd_list.cc 4484b5f175f144ffe3f505686eebf169941db916 +++ cmd_list.cc 17438456f9456eeeac4965cdb0f91878daeec4fe @@ -624,6 +624,8 @@ CMD(databases, "databases", "dbs", CMD_R E(app.lua.hook_get_default_database_locations(search_paths), origin::database, F("could not query default database locations")); + database_path_helper helper(app.lua); + for (vector::const_iterator i = search_paths.begin(); i != search_paths.end(); ++i) { @@ -649,6 +651,7 @@ CMD(databases, "databases", "dbs", CMD_R options opts; opts.dbname_type = unmanaged_db; opts.dbname = db_path; + opts.dbname_given = true; database db(opts, app.lua); @@ -667,57 +670,40 @@ CMD(databases, "databases", "dbs", CMD_R ); cout << F(":%s (in %s):") % managed_path % search_path << '\n'; - var_domain domain("database", origin::internal); - var_name name("known-workspaces", origin::internal); - var_key key(make_pair(domain, name)); + bool has_valid_workspaces = false; - bool has_known_workspaces = false; - if (db.var_exists(key)) + vector workspaces; + db.get_registered_workspaces(workspaces); + + for (vector::const_iterator k = workspaces.begin(); + k != workspaces.end(); ++k) { - var_value val; - db.get_var(key, val); + system_path workspace_path(*k); - vector workspaces; - split_into_lines(val(), workspaces); + options workspace_opts; + workspace::get_options(workspace_path, workspace_opts); - for (vector::const_iterator k = workspaces.begin(); - k != workspaces.end(); ++k) - { - system_path workspace_path(*k, origin::database); - if (!directory_exists(workspace_path / bookkeeping_root_component)) - { - L(FL("ignoring missing workspace '%s'") % workspace_path); - continue; - } + system_path workspace_db_path; + helper.get_database_path(workspace_opts, workspace_db_path); - options workspace_opts; - workspace::get_options(workspace_path, workspace_opts); + if (workspace_db_path != db_path) + { + L(FL("ignoring workspace '%s', expected database %s, " + "but has %s configured in _MTN/options") + % workspace_path % db_path % workspace_db_path); + continue; + } - system_path workspace_db_path = workspace_opts.dbname; - if (workspace_opts.dbname_type == managed_db) - resolve_db_alias(app.lua, - workspace_opts.dbname_alias, - workspace_db_path); + has_valid_workspaces = true; - if (workspace_db_path != db_path) - { - L(FL("ignoring workspace '%s', expected database %s, " - "but has %s configured in _MTN/options") - % workspace_path % db_path % workspace_db_path); - continue; - } + string workspace_branch = workspace_opts.branch(); + if (!workspace_opts.branch_given) + workspace_branch = _(""); - has_known_workspaces = true; - - string workspace_branch = workspace_opts.branch(); - if (!workspace_opts.branch_given) - workspace_branch = _(""); - - cout << F("\t%s (in %s)") % workspace_branch % workspace_path << '\n'; - } + cout << F("\t%s (in %s)") % workspace_branch % workspace_path << '\n'; } - if (!has_known_workspaces) + if (!has_valid_workspaces) cout << F("\tno known valid workspaces") << '\n'; } } ============================================================ --- database.cc a4a8ac204d750aa31eb5a45196ed6ba770e626f9 +++ database.cc d061178f713d11eaeb8258766a0652829ab56f6a @@ -489,70 +489,6 @@ database_impl::~database_impl() close(); } -void -resolve_db_alias(lua_hooks & lua, string const & alias, system_path & path) -{ - // we take care of this in the options code - I(alias.find(':') == 0); - - string pc = alias.substr(1); - size_t pos = pc.find('/'); - E(pos == string::npos, origin::user, - F("invalid database alias '%s'") % pc); - - pos = pc.rfind('.'); - if (pos == string::npos || pc.substr(pos + 1) != "mtn") - pc += ".mtn"; - - path_component basename(pc, origin::user); - vector candidates; - vector search_paths; - - E(lua.hook_get_default_database_locations(search_paths), origin::database, - F("could not query default database locations")); - - for (vector::const_iterator i = search_paths.begin(); - i != search_paths.end(); ++i) - { - if (file_exists((*i) / basename)) - { - candidates.push_back((*i) / basename); - continue; - } - } - - MM(candidates); - - // if we did not found the database anywhere, use the first - // available default path to possible save it there - if (candidates.size() == 0) - { - path = (*search_paths.begin()) / basename; - L(FL("no managed path candidates found, using '%s'") % path); - return; - } - - if (candidates.size() == 1) - { - path = (*candidates.begin()); - L(FL("one managed path candidate found: %s") % path); - return; - } - - if (candidates.size() > 1) - { - string err = - (F("the managed database name ':%s' has multiple " - "ambiguous expansions:") % pc).str(); - - for (vector::const_iterator i = candidates.begin(); - i != candidates.end(); ++i) - err += ("\n " + (*i).as_internal()); - - E(false, origin::user, i18n_format(err)); - } -} - database_cache database::dbcache; database::database(app_state & app) @@ -570,9 +506,9 @@ database::init() void database::init() { - system_path dbpath = opts.dbname; - if (opts.dbname_type == managed_db) - resolve_db_alias(lua, opts.dbname_alias, dbpath); + database_path_helper helper(lua); + system_path dbpath; + helper.get_database_path(opts, dbpath); if (dbcache.find(dbpath) == dbcache.end()) { @@ -623,10 +559,8 @@ database::create_if_not_exists() { if (!opts.dbname_given) { - string alias; - E(lua.hook_get_default_database_alias(alias) || alias.empty(), - origin::user, F("could not query default database alias")); - resolve_db_alias(lua, alias, imp->filename); + database_path_helper helper(lua); + helper.get_default_database_path(imp->filename); imp->type = managed_db; } @@ -4391,16 +4325,18 @@ database::clear_var(var_key const & key) % blob(key.second())); } +#define KNOWN_WORKSPACES_KEY \ + var_key(make_pair( \ + var_domain("database", origin::internal), \ + var_name("known-workspaces", origin::internal) \ + )) + void database::register_workspace(system_path const & path) { - var_domain domain("database", origin::internal); - var_name name("known-workspaces", origin::internal); - var_key key(make_pair(domain, name)); - var_value val; - if (var_exists(key)) - get_var(key, val); + if (var_exists(KNOWN_WORKSPACES_KEY)) + get_var(KNOWN_WORKSPACES_KEY, val); vector workspaces; split_into_lines(val(), workspaces); @@ -4415,20 +4351,16 @@ database::register_workspace(system_path string ws; join_lines(workspaces, ws); - set_var(key, var_value(ws, origin::internal)); + set_var(KNOWN_WORKSPACES_KEY, var_value(ws, origin::internal)); } void database::unregister_workspace(system_path const & path) { - var_domain domain("database", origin::internal); - var_name name("known-workspaces", origin::internal); - var_key key(make_pair(domain, name)); - - if (var_exists(key)) + if (var_exists(KNOWN_WORKSPACES_KEY)) { var_value val; - get_var(key, val); + get_var(KNOWN_WORKSPACES_KEY, val); vector workspaces; split_into_lines(val(), workspaces); @@ -4443,10 +4375,37 @@ database::unregister_workspace(system_pa string ws; join_lines(workspaces, ws); - set_var(key, var_value(ws, origin::internal)); + set_var(KNOWN_WORKSPACES_KEY, var_value(ws, origin::internal)); } } +void +database::get_registered_workspaces(vector & paths) +{ + if (var_exists(KNOWN_WORKSPACES_KEY)) + { + var_value val; + get_var(KNOWN_WORKSPACES_KEY, val); + + vector workspaces; + split_into_lines(val(), workspaces); + + for (vector::const_iterator i = workspaces.begin(); + i != workspaces.end(); ++i) + { + system_path workspace_path(*i, origin::database); + if (!directory_exists(workspace_path / bookkeeping_root_component)) + { + L(FL("ignoring missing workspace '%s'") % workspace_path); + continue; + } + paths.push_back(workspace_path); + } + } +} + +#undef KNOWN_WORKSPACES_KEY + // branches outdated_indicator @@ -4746,8 +4705,121 @@ conditional_transaction_guard::commit() committed = true; } +void +database_path_helper::get_database_path(options const & opts, system_path & path) +{ + if (!opts.dbname_given || + (opts.dbname.as_internal().empty() && + opts.dbname_alias.empty())) + { + L(FL("no database option given or options empty")); + return; + } + if (opts.dbname_type == unmanaged_db) + { + path = opts.dbname; + return; + } + E(opts.dbname_type == managed_db, origin::internal, + F("cannot determine full path for this database type")); + + path_component basename; + validate_and_clean_alias(opts.dbname_alias, basename); + + vector candidates; + vector search_paths; + + E(lua.hook_get_default_database_locations(search_paths) || search_paths.size() == 0, + origin::user, F("could not query default database locations")); + + for (vector::const_iterator i = search_paths.begin(); + i != search_paths.end(); ++i) + { + if (file_exists((*i) / basename)) + { + candidates.push_back((*i) / basename); + continue; + } + } + + MM(candidates); + + // if we did not found the database anywhere, use the first + // available default path to possible save it there + if (candidates.size() == 0) + { + path = (*search_paths.begin()) / basename; + L(FL("no path expansions found for '%s', using '%s'") + % opts.dbname_alias % path); + return; + } + + if (candidates.size() == 1) + { + path = (*candidates.begin()); + L(FL("one path expansion found for '%s': '%s'") + % opts.dbname_alias % path); + return; + } + + if (candidates.size() > 1) + { + string err = + (F("the database alias '%s' has multiple ambiguous expansions:") + % opts.dbname_alias).str(); + + for (vector::const_iterator i = candidates.begin(); + i != candidates.end(); ++i) + err += ("\n " + (*i).as_internal()); + + E(false, origin::user, i18n_format(err)); + } +} + +void +database_path_helper::get_default_database_path(system_path & path) +{ + vector default_paths; + E(lua.hook_get_default_database_locations(default_paths) || default_paths.size() == 0, + origin::user, F("could not query default database locations")); + + string alias; + E(lua.hook_get_default_database_alias(alias) || alias.empty(), + origin::user, F("could not query default database alias")); + + path_component basename; + validate_and_clean_alias(alias, basename); + + path = (*default_paths.begin()) / basename; +} + +void +database_path_helper::validate_and_clean_alias(string const & alias, path_component & pc) +{ + E(alias.find(':') == 0, origin::system, + F("invalid database alias '%s': does not start with a colon") % alias); + + string pure_alias = alias.substr(1); + E(pure_alias.size() > 0, origin::system, + F("invalid database alias '%s': must not be empty") % alias); + + size_t pos = pure_alias.rfind('.'); + if (pos == string::npos || pure_alias.substr(pos + 1) != "mtn") + pure_alias += ".mtn"; + + try + { + pc = path_component(pure_alias, origin::system); + } + catch (...) + { + E(false, origin::system, + F("invalid database alias '%s': does contain invalid characters") % alias); + } +} + // Local Variables: // mode: C++ // fill-column: 76 ============================================================ --- database.hh 8a1debf42e1ccc4263c755cb2c12b6a683dd563c +++ database.hh c60049b83091daa228f0f05487bb5d09218c14e3 @@ -379,6 +379,8 @@ public: void unregister_workspace(system_path const & path); + void get_registered_workspaces(std::vector & paths); + // // --== Completion ==-- // @@ -479,12 +481,6 @@ private: lua_hooks & lua; }; -// not a member function, because it has to be called in non-db -// context as well -void resolve_db_alias(lua_hooks & lua, - std::string const & alias, - system_path & path); - // not a member function, defined in database_check.cc void check_db(database & db); @@ -585,6 +581,20 @@ public: } }; +class database_path_helper +{ + lua_hooks & lua; +public: + database_path_helper(lua_hooks & l) : lua(l) {} + + void get_database_path(options const & opts, system_path & path); + + void get_default_database_path(system_path & path); + +private: + void validate_and_clean_alias(std::string const & alias, path_component & pc); +}; + #endif // __DATABASE_HH__ // Local Variables: ============================================================ --- lua_hooks.cc 24acf3a1517806ad897f64f2787381d5ececd47f +++ lua_hooks.cc 01bab6def621315198c957c066e3485417ffafc7 @@ -720,7 +720,7 @@ bool lua_hooks::hook_get_default_databas ll.extract_str(path).pop(); out.push_back(system_path(path, origin::user)); } - return ll.ok() && !out.empty(); + return ll.ok(); } bool lua_hooks::hook_hook_wrapper(string const & func_name, ============================================================ --- work.cc 939366f93f579840c44ed3979057f7a00bd92b07 +++ work.cc 8e9f5b11f99b845d327d237f1f542ebe72ab0e63 @@ -626,35 +626,33 @@ workspace::set_options(options const & o bool options_changed = false; - if ((!opts.dbname.as_internal().empty() || !opts.dbname_alias.empty()) && - (cur_opts.dbname != opts.dbname || cur_opts.dbname_alias != opts.dbname_alias)) - { - system_path dbpath = opts.dbname; - if (opts.dbname_type == managed_db) - resolve_db_alias(lua, opts.dbname_alias, dbpath); + database_path_helper helper(lua); + system_path old_db_path, new_db_path; - if (get_path_status(dbpath.as_internal()) == path::file) - { - // remove the currently registered workspace from the old - // database and add it to the new one - system_path current_workspace; - get_current_workspace(current_workspace); + helper.get_database_path(cur_opts, old_db_path); + helper.get_database_path(opts, new_db_path); - database old_db(cur_opts, lua); - old_db.unregister_workspace(current_workspace); + if (old_db_path != new_db_path && file_exists(new_db_path)) + { + // remove the currently registered workspace from the old + // database and add it to the new one + system_path current_workspace; + get_current_workspace(current_workspace); - database new_db(opts, lua); - new_db.register_workspace(current_workspace); + database old_db(cur_opts, lua); + old_db.unregister_workspace(current_workspace); - cur_opts.dbname_type = opts.dbname_type; - cur_opts.dbname_alias = opts.dbname_alias; - cur_opts.dbname = dbpath; - options_changed = true; - } + database new_db(opts, lua); + new_db.register_workspace(current_workspace); + + cur_opts.dbname_type = opts.dbname_type; + cur_opts.dbname_alias = opts.dbname_alias; + cur_opts.dbname = opts.dbname; + options_changed = true; } if (!opts.key_dir.as_internal().empty() && - get_path_status(opts.key_dir.as_internal()) == path::directory && + directory_exists(opts.key_dir) && cur_opts.key_dir != opts.key_dir) { cur_opts.key_dir = opts.key_dir;