Below is the file 'app_state.cc' from this revision. You can also download the file.
#include <iostream> #include <string> #include <vector> #include <cstdlib> // for strtoul() #include <boost/filesystem/path.hpp> #include <boost/filesystem/operations.hpp> #include <boost/filesystem/convenience.hpp> #include <boost/filesystem/exception.hpp> #include "app_state.hh" #include "database.hh" #include "file_io.hh" #include "sanity.hh" #include "transforms.hh" #include "work.hh" #include "platform.hh" // copyright (C) 2002, 2003 graydon hoare <graydon@pobox.com> // all rights reserved. // licensed to the public under the terms of the GNU GPL (>= 2) // see the file COPYING for details using namespace std; static string const database_option("database"); static string const branch_option("branch"); static string const key_option("key"); static string const keydir_option("keydir"); app_state::app_state() : branch_name(""), db(system_path()), keys(this), stdhooks(true), rcfiles(true), diffs(false), no_merges(false), set_default(false), verbose(false), date_set(false), search_root("/"), depth(-1), last(-1), next(-1), diff_format(unified_diff), diff_args_provided(false), use_lca(false), execute(false), bind_address(""), bind_port(""), missing(false), unknown(false), confdir(get_default_confdir()), have_set_key_dir(false), no_files(false) { db.set_app(this); lua.set_app(this); keys.set_key_dir(confdir / "keys"); } app_state::~app_state() { } void app_state::set_is_explicit_option (int option_id) { explicit_option_map[option_id] = true; } bool app_state::is_explicit_option(int option_id) const { std::map<int, bool>::const_iterator i = explicit_option_map.find(option_id); if (i == explicit_option_map.end()) return false; return i->second; } void app_state::allow_workspace() { L(FL("initializing from directory %s\n") % fs::initial_path().string()); found_workspace = find_and_go_to_workspace(search_root); if (found_workspace) { read_options(); if (!options[database_option]().empty()) { system_path dbname = system_path(options[database_option]); db.set_filename(dbname); } if (!options[keydir_option]().empty()) { system_path keydir = system_path(options[keydir_option]); set_key_dir(keydir); } if (branch_name().empty()) branch_name = options[branch_option]; L(FL("branch name is '%s'\n") % branch_name()); internalize_rsa_keypair_id(options[key_option], signing_key); if (global_sanity.filename.empty()) { bookkeeping_path dump_path; get_local_dump_path(dump_path); L(FL("setting dump path to %s\n") % dump_path); // the 'true' means that, e.g., if we're running checkout, then it's // okay for dumps to go into our starting working dir's MT rather // than the new workspace dir's MT. global_sanity.filename = system_path(dump_path, false); } } load_rcfiles(); } void app_state::require_workspace(std::string const & explanation) { N(found_workspace, F("workspace required but not found%s%s") % (explanation.empty() ? "" : "\n") % explanation); write_options(); } void app_state::create_workspace(system_path const & new_dir) { N(!new_dir.empty(), F("invalid directory ''")); L(FL("creating workspace in %s\n") % new_dir); mkdir_p(new_dir); go_to_workspace(new_dir); N(!directory_exists(bookkeeping_root), F("monotone bookkeeping directory '%s' already exists in '%s'\n") % bookkeeping_root % new_dir); L(FL("creating bookkeeping directory '%s' for workspace in '%s'\n") % bookkeeping_root % new_dir); mkdir_p(bookkeeping_root); make_branch_sticky(); write_options(); blank_user_log(); if (lua.hook_use_inodeprints()) enable_inodeprints(); load_rcfiles(); } void app_state::set_restriction(path_set const & valid_paths, vector<utf8> const & paths) { // FIXME: this was written before split_path, and only later kludged to // work with it. Could be much tidier if written with knowledge of // split_path. static file_path root = file_path_internal(""); restrictions.clear(); excludes.clear(); for (vector<utf8>::const_iterator i = paths.begin(); i != paths.end(); ++i) { file_path p = file_path_external(*i); split_path sp; p.split(sp); N(lua.hook_ignore_file(p) || p == root || valid_paths.find(sp) != valid_paths.end(), F("unknown path '%s'\n") % p); L(FL("'%s' added to restricted path set\n") % p); restrictions.insert(sp); } for (std::set<utf8>::const_iterator i = exclude_patterns.begin(); i != exclude_patterns.end(); ++i) { file_path p = file_path_external(*i); split_path sp; p.split(sp); N(lua.hook_ignore_file(p) || p == root || valid_paths.find(sp) != valid_paths.end(), F("unknown path '%s'\n") % p); L(FL("'%s' added to excluded path set\n") % p); excludes.insert(sp); } // if user supplied a depth but provided no paths // assume current directory if ((depth != -1) && restrictions.empty()) { file_path fp = file_path_external(utf8(".")); split_path sp; fp.split(sp); restrictions.insert(sp); } } bool app_state::restriction_requires_parent(split_path const & sp) { file_path path(sp); if (restrictions.empty()) return false; for (path_set::const_iterator i = restrictions.begin(); i != restrictions.end(); ++i) { // If sp is a parent of any member rs of the restriction, // we want to return true. split_path rs = *i; if (rs.size() < sp.size()) continue; rs.resize(sp.size()); if (rs == sp) return true; } return false; } bool app_state::restriction_includes(split_path const & sp) { // FIXME: this was written before split_path, and only later kludged to // work with it. Could be much tidier if written with knowledge of // split_path. file_path path(sp); static file_path root = file_path_internal(""); split_path sp_root; root.split(sp_root); if (restrictions.empty()) { if (!excludes.empty()) { if (excludes.find(sp_root) != excludes.end()) return false; split_path test = sp; while (!test.empty()) { L(FL("checking excluded path set for '%s'\n") % file_path(test)); path_set::const_iterator i = excludes.find(test); if (i != excludes.end()) { L(FL("path '%s' found in excluded path set; '%s' excluded\n") % file_path(test) % path); return false; } test.pop_back(); } } return true; } bool user_supplied_depth = (depth != -1); split_path test = sp; long branch_depth = 0; long max_depth = depth + 1; while (!test.empty()) { L(FL("checking restricted path set for '%s'\n") % file_path(test)); path_set::const_iterator i = restrictions.find(test); path_set::const_iterator j = excludes.find(test); if (i != restrictions.end()) { L(FL("path '%s' found in restricted path set; '%s' included\n") % file_path(test) % path); return true; } else if (j != excludes.end()) { L(FL("path '%s' found in excluded path set; '%s' excluded\n") % file_path(test) % path); return false; } if (user_supplied_depth && (max_depth == branch_depth)) return false; test.pop_back(); ++branch_depth; } // a path that normalizes to "." means that the restriction has been // essentially cleared (all files are included). rather than be // careful about what goes in to the restricted path set we just // check for this special case here. if (restrictions.find(sp_root) != restrictions.end()) { return (!user_supplied_depth) || (branch_depth <= max_depth); } return false; } void app_state::set_database(system_path const & filename) { if (!filename.empty()) db.set_filename(filename); options[database_option] = filename.as_internal(); } void app_state::set_key_dir(system_path const & filename) { if (!filename.empty()) { keys.set_key_dir(filename); have_set_key_dir = true; } options[keydir_option] = filename.as_internal(); } void app_state::set_branch(utf8 const & branch) { branch_name = branch(); } void app_state::make_branch_sticky() { options[branch_option] = branch_name(); if (found_workspace) { // already have a workspace, can (must) write options directly, // because no-one else will do so // if we don't have a workspace yet, then require_workspace (for // instance) will call write_options when it finds one. write_options(); } } void app_state::set_signing_key(utf8 const & key) { internalize_rsa_keypair_id(key, signing_key); options[key_option] = key; } void app_state::add_key_to_push(utf8 const & key) { rsa_keypair_id k; internalize_rsa_keypair_id(key, k); keys_to_push.push_back(k); } void app_state::set_root(system_path const & path) { require_path_is_directory(path, F("search root '%s' does not exist") % path, F("search root '%s' is not a directory\n") % path); search_root = path; L(FL("set search root to %s\n") % search_root); } void app_state::set_message(utf8 const & m) { message = m; } void app_state::set_message_file(utf8 const & m) { message_file = m; } void app_state::set_date(utf8 const & d) { try { // boost::posix_time is lame: it can parse "basic" ISO times, of the // form 20000101T120000, but not "extended" ISO times, of the form // 2000-01-01T12:00:00. So do something stupid to convert one to the // other. std::string tmp = d(); std::string::size_type pos = 0; while ((pos = tmp.find_first_of("-:")) != string::npos) tmp.erase(pos, 1); date = boost::posix_time::from_iso_string(tmp); date_set = true; } catch (std::exception &e) { N(false, F("failed to parse date string '%s': %s") % d % e.what()); } } void app_state::set_author(utf8 const & a) { author = a; } void app_state::set_depth(long d) { N(d >= 0, F("negative depth not allowed\n")); depth = d; } void app_state::set_last(long l) { N(l > 0, F("negative or zero last not allowed\n")); last = l; } void app_state::set_next(long l) { N(l > 0, F("negative or zero next not allowed\n")); next = l; } void app_state::set_pidfile(system_path const & p) { pidfile = p; } void app_state::add_revision(utf8 const & selector) { revision_selectors.push_back(selector); } void app_state::add_exclude(utf8 const & exclude_pattern) { exclude_patterns.insert(exclude_pattern); } void app_state::set_diff_format(diff_type dtype) { diff_format = dtype; } void app_state::set_diff_args(utf8 const & args) { diff_args_provided = true; diff_args = args; } void app_state::set_stdhooks(bool b) { stdhooks = b; } void app_state::set_rcfiles(bool b) { rcfiles = b; } void app_state::set_verbose(bool b) { verbose = b; } void app_state::add_rcfile(utf8 const & filename) { extra_rcfiles.push_back(filename); } void app_state::set_confdir(system_path const & cd) { confdir = cd; if (!have_set_key_dir) keys.set_key_dir(cd / "keys"); } system_path app_state::get_confdir() { return confdir; } // rc files are loaded after we've changed to the workspace so that // MT/monotonerc can be loaded between ~/.monotone/monotonerc and other // rcfiles void app_state::load_rcfiles() { // built-in rc settings are defaults if (stdhooks) lua.add_std_hooks(); // ~/.monotone/monotonerc overrides that, and // MT/monotonerc overrides *that* if (rcfiles) { system_path default_rcfile; bookkeeping_path workspace_rcfile; lua.default_rcfilename(default_rcfile); lua.workspace_rcfilename(workspace_rcfile); lua.load_rcfile(default_rcfile, false); lua.load_rcfile(workspace_rcfile, false); } // command-line rcfiles override even that for (vector<utf8>::const_iterator i = extra_rcfiles.begin(); i != extra_rcfiles.end(); ++i) { lua.load_rcfile(*i); } } void app_state::read_options() { bookkeeping_path o_path; get_options_path(o_path); try { if (path_exists(o_path)) { data dat; read_data(o_path, dat); read_options_map(dat, options); } } catch(std::exception & e) { W(F("Failed to read options file %s") % o_path); } } void app_state::write_options() { bookkeeping_path o_path; get_options_path(o_path); try { data dat; write_options_map(dat, options); write_data(o_path, dat); } catch(std::exception & e) { W(F("Failed to write options file %s") % o_path); } }