Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability to provide SDML Catalog path via an environment variable #18

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sdml-parse/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ sdml-errors = { version = "0.3.1", path = "../sdml-errors" }
search_path = "0.1.4"
serde = { version = "1.0.210", features = ["derive"] }
serde_json = "1.0.128"
serial_test = "3.2.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this down to dev-dependencies

tracing = "0.1.40"
tree-sitter = "0.23"
tree-sitter-sdml = "0.3.3"
Expand Down
21 changes: 19 additions & 2 deletions sdml-parse/src/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use sdml_errors::{Error, FileId};
use search_path::SearchPath;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
Expand Down Expand Up @@ -51,6 +52,9 @@ pub const SDML_FILE_EXTENSION_LONG: &str = "sdml";
/// The name used for resolver catalog files.
pub const SDML_CATALOG_FILE_NAME: &str = "sdml-catalog.json";

/// The environment variable used to override resolver catalog file location.
pub const SDML_CATALOG_FILE_VARIABLE: &str = "SDML_CATALOG";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would make this SDML_CATALOG_FILE, seems easier to understand, and you named the constant SDML_CATALOG_FILE_VARIABLE after all.


///
/// The loader is used to manage the process of creating an in-memory model from file-system resources.
///
Expand Down Expand Up @@ -149,8 +153,20 @@ impl Default for FsModuleResolver {
// 2. Add the current directory to the search path
search_path.prepend_cwd();

// 3. Load any catalog file found in the search path
let catalog = ModuleCatalog::load_from_current(true);
// 3. Load catalog file
let catalog = match env::var(SDML_CATALOG_FILE_VARIABLE) {
// If the environment variable is provided, load it from the location provided
Ok(catalog_file) => {
let catalog_file_path = PathBuf::from(catalog_file);
let module_catalog = ModuleCatalog::load_from_file(catalog_file_path.as_path());
if module_catalog.is_none() {
error!("The path to module catalog was provided through environment variable, yet it failed to load.");
}
module_catalog
},
// If the environment variable is not provided, load it from the current directory (or any parent directory)
_ => ModuleCatalog::load_from_current(true),
};

let _self = Self {
catalog,
Expand Down Expand Up @@ -435,6 +451,7 @@ impl ModuleCatalog {
/// exist.
///
fn load_from_file(file: &Path) -> Option<Self> {
trace!("ModuleCatalog::load_from_file({file:?})");
match std::fs::read_to_string(file) {
Ok(source) => match serde_json::from_str::<ModuleCatalog>(&source) {
Ok(mut catalog) => {
Expand Down
2 changes: 1 addition & 1 deletion sdml-parse/src/parse/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ fn parse_binary<'a>(
{
context.check_if_error(&node, RULE_NAME)?;
let value = context.node_source(&node)?;
let value = u8::from_str(value).expect("Invalid value for Byte");
let value = u8::from_str_radix(value, 16).expect("Invalid value for Byte");
result.push(value);
}

Expand Down
11 changes: 11 additions & 0 deletions sdml-parse/tests/catalog_examples/custom-catalog.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"base": "https://examples.sdml.io/",
"entries": {
"campaign": {
"item": {
"relative_url": "campaign#",
"relative_path": "../examples/entity_empty.sdm"
}
}
}
}
31 changes: 30 additions & 1 deletion sdml-parse/tests/examples/ron/annotation_single_binary.ron
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,36 @@ Module {
value: Simple(
Binary(
Binary(
[],
[
82,
50,
57,
118,
90,
67,
66,
67,
101,
87,
85,
103,
81,
51,
74,
49,
90,
87,
119,
103,
86,
50,
57,
121,
98,
71,
81,
75,
],
),
),
),
Expand Down
2 changes: 1 addition & 1 deletion sdml-parse/tests/test_examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ macro_rules! test_example {
));
let expected = ::std::path::PathBuf::from(
format!(
"{}/{}/{}.ron",
"{}/{}/ron/{}.ron",
MANIFEST_PATH,
TEST_PATH,
test_name
Expand Down
91 changes: 91 additions & 0 deletions sdml-parse/tests/test_load_catalog.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use sdml_core::{load::ModuleLoader, model::identifiers::Identifier, store::ModuleStore};
use sdml_parse::load::SDML_CATALOG_FILE_VARIABLE;
use serial_test::serial;
use std::str::FromStr;
use url::Url;

const MANIFEST_PATH: &str = env!("CARGO_MANIFEST_DIR");
const TEST_PATH: &str = "tests/catalog_examples";

const CATALOG_FILE: &str = "custom-catalog.json";
const MODULE_NAME: &str = "campaign";

fn set_env_variable(env_key: &str, env_value: Option<String>) {
match env_value {
Some(v) => std::env::set_var(env_key, v),
None => std::env::remove_var(env_key),
}
}

fn with_env_variable<F>(env_key: &str, env_value: Option<&str>, test: F)
where
F : FnOnce() + std::panic::UnwindSafe,
{
// Set the environment variable
let old_value = std::env::var(env_key).ok();

set_env_variable(env_key, env_value.map(|x| { String::from(x)}));

// Run the test, catching any panic
let result = std::panic::catch_unwind(|| {
test();
});

// Clean-up / restore environment variable
set_env_variable(env_key, old_value);

// Propagate the panic if it occurred
if let Err(err) = result {
std::panic::resume_unwind(err);
}
}

#[test]
#[serial]
fn test_load_without_catalogue() {
with_env_variable(SDML_CATALOG_FILE_VARIABLE, None, || {
let mut cache = ::sdml_core::store::InMemoryModuleCache::default().with_stdlib();
let mut loader = ::sdml_parse::load::FsModuleLoader::default();
let module_name = Identifier::from_str(MODULE_NAME).unwrap();

loader.load(
&module_name,
loader.get_file_id(&module_name),
&mut cache,
true,
).expect_err("Error: Should have failed to load the module.");
});
}

#[test]
#[serial]
fn test_load_with_catalogue() {
let catalog_path = ::std::path::PathBuf::from(
format!(
"{}/{}/{}",
MANIFEST_PATH,
TEST_PATH,
CATALOG_FILE,
));

with_env_variable(SDML_CATALOG_FILE_VARIABLE, catalog_path.to_str(), || {
let mut cache = ::sdml_core::store::InMemoryModuleCache::default().with_stdlib();
let mut loader = ::sdml_parse::load::FsModuleLoader::default();
let module_name = Identifier::from_str(MODULE_NAME).unwrap();

loader.load(
&module_name,
loader.get_file_id(&module_name),
&mut cache,
true,
).expect("Error: Should have been able to load the module.");

let module = cache
.get(&module_name)
.expect("Error: Module not found in cache.");

let url = Url::from_str("https://examples.sdml.io/campaign#").ok();

assert_eq!(module.base_uri().map(|x| { x.value().clone() }), url);
});
}