Skip to content

Commit

Permalink
Merge pull request #478 from luketpeterson/main
Browse files Browse the repository at this point in the history
Creating default Environment config files only when explicitly direct…
  • Loading branch information
luketpeterson authored Nov 2, 2023
2 parents 5d52cf4 + 995d29d commit b7e55c4
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 19 deletions.
16 changes: 14 additions & 2 deletions c/src/metta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -926,7 +926,7 @@ pub extern "C" fn metta_nth_search_path(metta: *const metta_t, idx: usize, buf:
let path = metta.search_paths().nth(idx);
match path {
Some(path) => write_into_buf(path.display(), buf, buf_len),
None => 0
None => write_into_buf("", buf, buf_len) //Write just the terminator char, if there is room
}
}

Expand Down Expand Up @@ -1217,7 +1217,7 @@ pub extern "C" fn runner_state_current_results(state: *const runner_state_t,
pub extern "C" fn environment_config_dir(buf: *mut c_char, buf_len: usize) -> usize {
match Environment::common_env().config_dir() {
Some(path) => write_into_buf(path.display(), buf, buf_len),
None => 0
None => write_into_buf("", buf, buf_len) //Write just the terminator char, if there is room
}
}

Expand Down Expand Up @@ -1338,6 +1338,18 @@ pub extern "C" fn env_builder_set_config_dir(builder: *mut env_builder_t, path:
*builder_arg_ref = builder.into();
}

/// @brief Configures the environment to create the config dir if it doesn't already exist
/// @ingroup environment_group
/// @param[in] builder A pointer to the in-process environment builder state
///
#[no_mangle]
pub extern "C" fn env_builder_create_config_dir(builder: *mut env_builder_t) {
let builder_arg_ref = unsafe{ &mut *builder };
let builder = core::mem::replace(builder_arg_ref, env_builder_t::null()).into_inner();
let builder = builder.create_config_dir();
*builder_arg_ref = builder.into();
}

/// @brief Configures the environment so that no config directory will be read nor created
/// @ingroup environment_group
/// @param[in] builder A pointer to the in-process environment builder state
Expand Down
53 changes: 41 additions & 12 deletions lib/src/metta/runner/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ impl Environment {
pub struct EnvBuilder {
env: Environment,
no_cfg_dir: bool,
create_cfg_dir: bool,
}

impl EnvBuilder {
Expand All @@ -97,6 +98,7 @@ impl EnvBuilder {
Self {
env: Environment::new(),
no_cfg_dir: false,
create_cfg_dir: false,
}
}

Expand Down Expand Up @@ -124,9 +126,23 @@ impl EnvBuilder {
self
}

/// Configures the environment to create a config directory with default config files, if no directory is found
///
/// NOTE: If the config directory exists but some config files are missing, default files will not be created.
pub fn create_config_dir(mut self) -> Self {
self.create_cfg_dir = true;
if self.no_cfg_dir {
panic!("Fatal Error: create_config_dir is incompatible with set_no_config_dir");
}
self
}

/// Configures the Environment not to load nor create any config files
pub fn set_no_config_dir(mut self) -> Self {
self.no_cfg_dir = true;
if self.create_cfg_dir {
panic!("Fatal Error: set_no_config_dir is incompatible with create_config_dir");
}
if self.env.config_dir.is_some() {
panic!("Fatal Error: set_config_dir is incompatible with set_no_config_dir");
}
Expand Down Expand Up @@ -169,12 +185,12 @@ impl EnvBuilder {
///
/// NOTE: Creating owned Environments is usually not necessary. It is usually sufficient to use the [common_env] method.
pub(crate) fn build(self) -> Environment {

let mut env = self.env;

//Init the logger. This will have no effect if the logger has already been initialized
let _ = env_logger::builder().is_test(env.is_test).try_init();

//Construct the platform-specific config dir location, if an explicit location wasn't provided
if !self.no_cfg_dir {
if env.config_dir.is_none() {
match ProjectDirs::from("io", "TrueAGI", "metta") {
Expand All @@ -190,27 +206,40 @@ impl EnvBuilder {

if let Some(config_dir) = &env.config_dir {

//Create the modules dir inside the config dir, if it doesn't already exist.
// This will create the cfg_dir iteslf in the process
let modules_dir = config_dir.join("modules");
std::fs::create_dir_all(&modules_dir).unwrap();
let init_metta_path = config_dir.join("init.metta");

//Push the "modules" dir, as the last place to search after the other paths that were specified
//TODO: the config.metta file will be able to append / modify the search paths, and can choose not to
// include the "modules" dir in the future.
env.extra_include_paths.push(modules_dir);
//Create the default config dir, if that part of our directive
if self.create_cfg_dir && !config_dir.exists() {

//Create the default init.metta file if it doesn't already exist
let init_metta_path = config_dir.join("init.metta");
if !init_metta_path.exists() {
//Create the modules dir inside the config dir
// This will create the cfg_dir iteslf in the process
std::fs::create_dir_all(&modules_dir).unwrap();

//Create the default init.metta file
let mut file = fs::OpenOptions::new()
.create(true)
.write(true)
.open(&init_metta_path)
.expect(&format!("Error creating default init file at {init_metta_path:?}"));
file.write_all(&DEFAULT_INIT_METTA).unwrap();
}
env.init_metta_path = Some(init_metta_path);

//If the config_dir in the Environment still doesn't exist (and we couldn't create it), then set it to None
if !config_dir.exists() {
env.config_dir = None;
}

//Push the "modules" dir, as the last place to search after the other paths that were specified
//TODO: the config.metta file should be able to append / modify the search paths, and can choose not to
// include the "modules" dir in the future.
if modules_dir.exists() {
env.extra_include_paths.push(modules_dir);
}

if init_metta_path.exists() {
env.init_metta_path = Some(init_metta_path);
}
}

//TODO: This line below is a stop-gap to match old behavior
Expand Down
8 changes: 5 additions & 3 deletions python/hyperon/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,22 +203,24 @@ def config_dir():
else:
return None

def init_common_env(working_dir = None, config_dir = None, disable_config = False, is_test = False, include_paths = []):
def init_common_env(working_dir = None, config_dir = None, create_config = False, disable_config = False, is_test = False, include_paths = []):
"""Initialize the common environment with the supplied args"""
builder = Environment.custom_env(working_dir, config_dir, disable_config, is_test, include_paths)
builder = Environment.custom_env(working_dir, config_dir, create_config, disable_config, is_test, include_paths)
return hp.env_builder_init_common_env(builder)

def test_env():
"""Returns an EnvBuilder object specifying a unit-test environment, that can be used to init a MeTTa runner"""
return hp.env_builder_use_test_env()

def custom_env(working_dir = None, config_dir = None, disable_config = False, is_test = False, include_paths = []):
def custom_env(working_dir = None, config_dir = None, create_config = False, disable_config = False, is_test = False, include_paths = []):
"""Returns an EnvBuilder object that can be used to init a MeTTa runner, if you need multiple environments to coexist in the same process"""
builder = hp.env_builder_start()
if (working_dir is not None):
hp.env_builder_set_working_dir(builder, working_dir)
if (config_dir is not None):
hp.env_builder_set_config_dir(builder, config_dir)
if (create_config):
hp.env_builder_create_config_dir(builder)
if (disable_config):
hp.env_builder_disable_config_dir(builder)
if (is_test):
Expand Down
1 change: 1 addition & 0 deletions python/hyperonpy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,7 @@ PYBIND11_MODULE(hyperonpy, m) {
m.def("env_builder_init_common_env", [](EnvBuilder builder) { return env_builder_init_common_env(builder.obj); }, "Finish initialization of the common environment");
m.def("env_builder_set_working_dir", [](EnvBuilder& builder, std::string path) { env_builder_set_working_dir(builder.ptr(), path.c_str()); }, "Sets the working dir in the environment");
m.def("env_builder_set_config_dir", [](EnvBuilder& builder, std::string path) { env_builder_set_config_dir(builder.ptr(), path.c_str()); }, "Sets the config dir in the environment");
m.def("env_builder_create_config_dir", [](EnvBuilder& builder) { env_builder_create_config_dir(builder.ptr()); }, "Creates the config dir if it doesn't exist");
m.def("env_builder_disable_config_dir", [](EnvBuilder& builder) { env_builder_disable_config_dir(builder.ptr()); }, "Disables the config dir in the environment");
m.def("env_builder_set_is_test", [](EnvBuilder& builder, bool is_test) { env_builder_set_is_test(builder.ptr(), is_test); }, "Disables the config dir in the environment");
m.def("env_builder_add_include_path", [](EnvBuilder& builder, std::string path) { env_builder_add_include_path(builder.ptr(), path.c_str()); }, "Adds an include path to the environment");
Expand Down
2 changes: 1 addition & 1 deletion python/tests/test_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def __init__(self, methodName):
super().__init__(methodName)

def testEnvironment(self):
self.assertTrue(Environment.init_common_env(config_dir = "/tmp/test_dir"))
self.assertTrue(Environment.init_common_env(config_dir = "/tmp/test_dir", create_config = True))
self.assertEqual(Environment.config_dir(), "/tmp/test_dir")

self.assertFalse(Environment.init_common_env(disable_config = True))
1 change: 1 addition & 0 deletions repl/src/metta_shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ pub mod metta_interface_mod {
pub fn init_common_env(working_dir: PathBuf, include_paths: Vec<PathBuf>) -> Result<MettaShim, String> {
EnvBuilder::new()
.set_working_dir(Some(&working_dir))
.create_config_dir()
.add_include_paths(include_paths)
.init_common_env();

Expand Down
2 changes: 1 addition & 1 deletion repl/src/py_shim.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from hyperon import *

def init_metta(working_dir, include_paths):
Environment.init_common_env(working_dir = working_dir, include_paths = include_paths)
Environment.init_common_env(working_dir = working_dir, create_config = True, include_paths = include_paths)
return MeTTa()

def load_metta_module(metta, mod_path):
Expand Down

0 comments on commit b7e55c4

Please sign in to comment.