# # # patch "cmd_automate.cc" # from [d3f3f46e6b6830b5d8c9b9f68f1d573dfad59126] # to [5e97d510878071cf512adf39171ac1342111fa40] # # patch "cmd_merging.cc" # from [97b6b695edfc97d361f655be497353a716976f54] # to [bc106507603d09f5dbe9e2daf79204a5b909b342] # # patch "cmd_netsync.cc" # from [ecf459ce845f38db058d30ad04910d57ee1310f2] # to [573d9eb961a43cd63cd30ec56e83b529e47c3743] # # patch "cmd_ws_commit.cc" # from [10d33763a838c34d36cdacf987678905f77762be] # to [7106df2a02e67e70dde410ca1072303436adbe08] # # patch "database.cc" # from [4a62da575517d7a24bdb94af91640add74741890] # to [e5168e78a5d76befca354f7ae8ba2d5595a20bd1] # # patch "database.hh" # from [c7ae2340052b1205f3615f416adb1c58917abfd5] # to [5f6aa0b6b7f916cc8887f44b1b81e5ed0be479c1] # # patch "monotone.cc" # from [a925c994fd30f1efa53648052c8b6e91d63169fd] # to [ac30d742adb437d3f60283f23d06fc20364ea3d3] # # patch "network/automate_session.cc" # from [97588a34b995e3e7886345f443bd0fa70d6053cb] # to [ef677d06324365607b14c1b992b04850697ef7eb] # # patch "options_list.hh" # from [4f0483db8e18e652824cd16c29d34ff3c8f31c79] # to [442671f8b8d16e2c3228f9bb51f015f4fd4105d8] # # patch "vocab.hh" # from [e572a01a4185be56e57287b83efdc44061c2baef] # to [8d49fa12d7b4a5ed0426fd9fa8c71aa82cb1dfb9] # # patch "work.cc" # from [28266a7fbb698d94c998047e52842b220b37756d] # to [496cfc57b72c8835e104cc671bf4df816aa62d09] # # patch "work.hh" # from [021031510460f3cdc3762460937d94b575f04154] # to [a5aa65db2b9ae4f43f41a265280df76450e003fb] # ============================================================ --- cmd_automate.cc d3f3f46e6b6830b5d8c9b9f68f1d573dfad59126 +++ cmd_automate.cc 5e97d510878071cf512adf39171ac1342111fa40 @@ -329,7 +329,7 @@ CMD_AUTOMATE_NO_STDIO(stdio, "", // usually, if a command succeeds, any of its workspace-relevant // options are saved back to _MTN/options, this shouldn't be // any different here - workspace::maybe_set_options(app.opts); + workspace::maybe_set_options(app.opts, app.lua); // restore app.opts app.opts = original_opts; @@ -477,7 +477,7 @@ LUAEXT(mtn_automate, ) // usually, if a command succeeds, any of its workspace-relevant // options are saved back to _MTN/options, this shouldn't be // any different here - workspace::maybe_set_options(app_p->opts); + workspace::maybe_set_options(app_p->opts, app_p->lua); // allow further calls app_p->mtn_automate_allowed = true; ============================================================ --- cmd_merging.cc 97b6b695edfc97d361f655be497353a716976f54 +++ cmd_merging.cc bc106507603d09f5dbe9e2daf79204a5b909b342 @@ -241,7 +241,7 @@ update(app_state & app, 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. - work.set_options(app.opts, true); + work.set_options(app.opts, app.lua, true); return; } @@ -331,7 +331,7 @@ update(app_state & app, work.put_update_id(old_rid); work.put_work_rev(remaining); work.maybe_update_inodeprints(db); - work.set_options(app.opts, true); + work.set_options(app.opts, app.lua, true); if (switched_branch) P(F("switched branch; next commit will use branch %s") % app.opts.branch()); ============================================================ --- cmd_netsync.cc ecf459ce845f38db058d30ad04910d57ee1310f2 +++ cmd_netsync.cc 573d9eb961a43cd63cd30ec56e83b529e47c3743 @@ -289,7 +289,7 @@ CMD_AUTOMATE_NO_STDIO(remote_stdio, { W(F("No database given; assuming ':memory:' database. This means that we can't\n" "verify the server key, because we have no record of what it should be.")); - app.opts.dbname_is_memory = true; + app.opts.dbname_type = memory_db; } database db(app); @@ -420,7 +420,7 @@ CMD_AUTOMATE_NO_STDIO(remote, { W(F("No database given; assuming ':memory:' database. This means that we can't\n" "verify the server key, because we have no record of what it should be.")); - app.opts.dbname_is_memory = true; + app.opts.dbname_type = memory_db; } database db(app); @@ -606,7 +606,7 @@ CMD(sync, "sync", "", CMD_REF(network), { // Write workspace options, including key; this is the simplest way to // fix a "found multiple keys" error reported by sync. - workspace::set_options(app.opts); + workspace::set_options(app.opts, app.lua); } run_netsync_protocol(app, app.opts, app.lua, project, keys, @@ -631,7 +631,7 @@ CMD_AUTOMATE(sync, N_("[ADDRESS[:PORTNUM { // Write workspace options, including key; this is the simplest way to // fix a "found multiple keys" error reported by sync. - workspace::set_options(app.opts); + workspace::set_options(app.opts, app.lua); } run_netsync_protocol(app, app.opts, app.lua, project, keys, ============================================================ --- cmd_ws_commit.cc 10d33763a838c34d36cdacf987678905f77762be +++ cmd_ws_commit.cc 7106df2a02e67e70dde410ca1072303436adbe08 @@ -1328,7 +1328,7 @@ CMD(commit, "commit", "ci", CMD_REF(work } // the workspace should remember the branch we just committed to. - work.set_options(app.opts, true); + work.set_options(app.opts, app.lua, true); // the work revision is now whatever changes remain on top of the revision // we just checked in. ============================================================ --- database.cc 4a62da575517d7a24bdb94af91640add74741890 +++ database.cc e5168e78a5d76befca354f7ae8ba2d5595a20bd1 @@ -208,7 +208,7 @@ public: // for scoped_ptr's sake public: - explicit database_impl(system_path const & f, bool mem, lua_hooks & lua, + explicit database_impl(system_path const & f, db_type t, system_path const & roster_cache_performance_log); ~database_impl(); @@ -218,8 +218,7 @@ private: // --== Opening the database and schema checking ==-- // system_path filename; - bool use_memory_db; - lua_hooks & lua; + db_type type; struct sqlite3 * __sql; void install_functions(); @@ -228,7 +227,6 @@ private: void check_filename(); void check_db_exists(); void check_db_nonexistent(); - bool find_database_file(); void open(); void close(); void check_format(); @@ -460,11 +458,10 @@ sqlite3_hex_fn(sqlite3_context *f, int n } #endif -database_impl::database_impl(system_path const & f, bool mem, lua_hooks & lua, +database_impl::database_impl(system_path const & f, db_type t, system_path const & roster_cache_performance_log) : filename(f), - use_memory_db(mem), - lua(lua), + type(t), __sql(NULL), transaction_level(0), roster_cache(constants::db_roster_cache_sz, @@ -495,6 +492,72 @@ struct database_cache map > dbs; }; +void +resolve_managed_path(lua_hooks & lua, system_path & path) +{ + size_t pos = path.as_internal().rfind(':'); + // windows paths are not managed paths either + if (pos == std::string::npos || pos == 1) + return; + + std::string pc = path.as_internal().substr(pos + 1); + pos = pc.find('/'); + E(pos == std::string::npos, origin::user, + F("invalid managed database name '%s'") % pc); + + pos = pc.rfind('.'); + if (pos == std::string::npos || pc.substr(pos + 1) != "mtn") + pc += ".mtn"; + + path_component basename(pc, origin::user); + std::vector candidates; + std::vector search_paths; + + E(lua.hook_get_default_database_locations(search_paths), origin::database, + F("could not query default database locations")); + + for (std::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 (std::vector::const_iterator i = candidates.begin(); + i != candidates.end(); ++i) + err += ("\n " + (*i).as_internal()); + + E(false, origin::user, i18n_format(err)); + } +} + database::database(app_state & app) : lua(app.lua) #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) @@ -507,9 +570,15 @@ database::database(app_state & app) boost::shared_ptr & i = app.dbcache->dbs[app.opts.dbname]; if (!i) - i.reset(new database_impl(app.opts.dbname, app.opts.dbname_is_memory, - lua, app.opts.roster_cache_performance_log)); + { + system_path dbpath = app.opts.dbname; + if (app.opts.dbname_type == managed_db) + resolve_managed_path(app.lua, dbpath); + i.reset(new database_impl(dbpath, app.opts.dbname_type, + app.opts.roster_cache_performance_log)); + } + imp = i; } @@ -525,7 +594,7 @@ database::is_dbfile(any_path const & fil bool database::is_dbfile(any_path const & file) { - if (imp->use_memory_db) + if (imp->type == memory_db) return false; system_path fn(file); // canonicalize bool same = (imp->filename == fn); @@ -537,7 +606,7 @@ database::database_specified() bool database::database_specified() { - return imp->use_memory_db || !imp->filename.empty(); + return imp->type == memory_db || !imp->filename.empty(); } void @@ -616,7 +685,7 @@ database_impl::sql(enum open_mode mode) { if (! __sql) { - if (use_memory_db) + if (type == memory_db) { open(); @@ -4446,8 +4515,7 @@ database_impl::check_db_exists() return; case path::nonexistent: - E(find_database_file(), origin::user, F("database %s does not exist") % filename); - return; + E(false, origin::user, F("database %s does not exist") % filename); case path::directory: if (directory_is_workspace(filename)) @@ -4479,79 +4547,21 @@ database_impl::check_db_nonexistent() } - -bool -database_impl::find_database_file() -{ - // exit early if the file is found - if (file_exists(filename)) - return true; - - // only pick the base name of the non-existing path - path_component basename = filename.basename(); - std::vector candidates; - std::vector search_paths; - - E(lua.hook_get_default_database_locations(search_paths), origin::system, - F("could not query default database locations")); - - for (std::vector::const_iterator i = search_paths.begin(); - i != search_paths.end(); ++i) - { - if (file_exists((*i) / basename)) - { - candidates.push_back((*i) / basename); - continue; - } - - size_t pos = basename().rfind('.'); - if (pos != std::string::npos && basename().substr(pos + 1) != "mtn") - { - path_component basename_with_ext( - basename() + ".mtn", origin::internal - ); - - if (file_exists((*i) / basename_with_ext)) - { - candidates.push_back((*i) / basename_with_ext); - continue; - } - } - } - - MM(candidates); - - if (candidates.size() == 0) - return false; - - if (candidates.size() == 1) - return true; - - if (candidates.size() > 1) - { - string err = - (F("the database '%s' has multiple ambiguous expansions:") % filename).str(); - - for (std::vector::const_iterator i = candidates.begin(); - i != candidates.end(); ++i) - err += ("\n" + (*i).as_internal()); - - E(false, origin::user, i18n_format(err)); - } - - I(false); -} - void database_impl::open() { I(!__sql); std::string to_open; - if (use_memory_db) + if (type == memory_db) to_open = ":memory:"; else - to_open = filename.as_external(); + { + system_path base_dir = filename.dirname(); + if (!directory_exists(base_dir)) + mkdir_p(base_dir); + to_open = filename.as_external(); + } if (sqlite3_open(to_open.c_str(), &__sql) == SQLITE_NOMEM) throw std::bad_alloc(); ============================================================ --- database.hh c7ae2340052b1205f3615f416adb1c58917abfd5 +++ database.hh 5f6aa0b6b7f916cc8887f44b1b81e5ed0be479c1 @@ -464,6 +464,10 @@ private: #endif }; +// not a member function, because it has to be called in non-db +// context as well +void resolve_managed_path(lua_hooks & lua, system_path & path); + // not a member function, defined in database_check.cc void check_db(database & db); ============================================================ --- monotone.cc a925c994fd30f1efa53648052c8b6e91d63169fd +++ monotone.cc ac30d742adb437d3f60283f23d06fc20364ea3d3 @@ -287,7 +287,7 @@ cpp_main(int argc, char ** argv) commands::process(app, cmd, app.opts.args); - workspace::maybe_set_options(app.opts); + workspace::maybe_set_options(app.opts, app.lua); // The command will raise any problems itself through // exceptions. If we reach this point, it is because it ============================================================ --- network/automate_session.cc 97588a34b995e3e7886345f443bd0fa70d6053cb +++ network/automate_session.cc ef677d06324365607b14c1b992b04850697ef7eb @@ -261,7 +261,7 @@ bool automate_session::do_work(transacti // usually, if a command succeeds, any of its workspace-relevant // options are saved back to _MTN/options, this shouldn't be // any different here - workspace::maybe_set_options(app.opts); + workspace::maybe_set_options(app.opts, app.lua); // restore app.opts app.opts = original_opts; ============================================================ --- options_list.hh 4f0483db8e18e652824cd16c29d34ff3c8f31c79 +++ options_list.hh 442671f8b8d16e2c3228f9bb51f015f4fd4105d8 @@ -227,12 +227,17 @@ GOPT(format_dates, "no-format-dates", bo } #endif -OPTVAR(globals, bool, dbname_is_memory, false); + +OPTVAR(globals, db_type, dbname_type, false); GOPT(dbname, "db,d", system_path, , gettext_noop("set name of database")) #ifdef option_bodies { dbname = system_path(arg, origin::user); - dbname_is_memory = (arg == ":memory:"); + dbname_type = unmanaged_db; + if (arg == ":memory:") + dbname_type = memory_db; + else if (arg.size() > 1 && arg.substr(0, 1) == ":") + dbname_type = managed_db; } #endif ============================================================ --- vocab.hh e572a01a4185be56e57287b83efdc44061c2baef +++ vocab.hh 8d49fa12d7b4a5ed0426fd9fa8c71aa82cb1dfb9 @@ -111,6 +111,14 @@ enum date_format_spec date_time_short }; +// to distinguish different database types +enum db_type +{ + memory_db, + managed_db, + unmanaged_db +}; + // do these belong here? inline bool null_id(id const & i) ============================================================ --- work.cc 28266a7fbb698d94c998047e52842b220b37756d +++ work.cc 496cfc57b72c8835e104cc671bf4df816aa62d09 @@ -159,7 +159,7 @@ workspace::create_workspace(options cons mkdir_p(bookkeeping_root); workspace::found = true; - workspace::set_options(opts, true); + workspace::set_options(opts, lua, true); workspace::write_format(); data empty; @@ -549,10 +549,10 @@ void } void -workspace::maybe_set_options(options const & opts) +workspace::maybe_set_options(options const & opts, lua_hooks & lua) { if (workspace::found && workspace::used) - set_options(opts, false); + set_options(opts, lua, false); } // This function should usually be called at the (successful) @@ -560,7 +560,7 @@ void // if this is a valid sqlite file and if it contains the correct identifier, // so be warned that you do not call this too early void -workspace::set_options(options const & opts, bool branch_is_sticky) +workspace::set_options(options const & opts, lua_hooks & lua, bool branch_is_sticky) { E(workspace::found, origin::user, F("workspace required but not found")); @@ -582,11 +582,17 @@ workspace::set_options(options const & o bool options_changed = false; if (!opts.dbname.as_internal().empty() && - get_path_status(opts.dbname.as_internal()) == path::file && workspace_database != opts.dbname) { - workspace_database = opts.dbname; - options_changed = true; + system_path dbpath = opts.dbname; + resolve_managed_path(lua, dbpath); + + if (get_path_status(dbpath.as_internal()) == path::file) + { + // FIXME: save the alias / managed name here, not the absolute path + workspace_database = dbpath; + options_changed = true; + } } if (!opts.key_dir.as_internal().empty() && ============================================================ --- work.hh 021031510460f3cdc3762460937d94b575f04154 +++ work.hh a5aa65db2b9ae4f43f41a265280df76450e003fb @@ -233,8 +233,10 @@ public: static void get_options(options & opts); static void get_database_option(system_path const & workspace_root, system_path & database_option); - static void set_options(options const & opts, bool branch_is_sticky = false); - static void maybe_set_options(options const & opts); + static void set_options(options const & opts, + lua_hooks & lua, + bool branch_is_sticky = false); + static void maybe_set_options(options const & opts, lua_hooks & lua); static void print_option(utf8 const & opt, std::ostream & output); // the "bisect" infromation file is a file that records current status