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

Support for loading templates from the file system or from an embedded representation in the app's binary. #171

Merged
merged 23 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
dc096ce
feat(forge): Add FileLoader abstraction to load files from a the file…
lquerel May 23, 2024
04e3889
chore(test): Test most of the registry sub-commands.
lquerel May 24, 2024
ac0e457
chore(test): Test diagnostic init
lquerel May 24, 2024
8066f3f
Merge branch 'main' into embedded-diag-templates
lquerel May 24, 2024
ebe1a90
feat(forge): Add overload mechanism support in EmbeddedFileLoader.
lquerel May 24, 2024
1c260a5
chore(test): Improve test coverage
lquerel May 24, 2024
2a34b43
chore(test): Improve test coverage
lquerel May 25, 2024
7ce0330
chore(test): Improve test coverage
lquerel May 26, 2024
03e654c
chore(docker): Add default_diagnostic_templates
lquerel May 28, 2024
3dcce6f
chore(docker): Add log in Dockerfile to debug docker build issue
lquerel May 28, 2024
4753a09
chore(docker): Add log in Dockerfile to debug docker build issue
lquerel May 28, 2024
99e4ff2
chore(docker): Add log in Dockerfile to debug docker build issue
lquerel May 28, 2024
f32c7e3
chore(docker): Add log in Dockerfile to debug docker build issue
lquerel May 28, 2024
3d86ccd
chore(forge): Simplify FileLoader interface based on @jsuereth sugges…
lquerel May 28, 2024
3c3f368
chore(update_markdown): Add unit test to the registry update-markdown…
lquerel May 28, 2024
0d3dc79
chore(docker): Fix the dockerfile to embedded the default_diagnostic_…
lquerel May 28, 2024
84f556d
chore(check-external-types): Fix nightly version for check-external-t…
lquerel May 28, 2024
9b8e7a7
feat(forge): Move Send+Sync inside the TemplateEngine instead of in t…
lquerel May 28, 2024
37968ce
Merge branch 'main' into embedded-diag-templates
lquerel May 28, 2024
e241e08
chore(diagnostic): Generate diagnostics from CompoundErrors.
lquerel May 28, 2024
7bc1240
chore(diagnostic): Fix diagnostic report in weaver_semconv_gen
lquerel May 28, 2024
4b91adc
chore(fmt): Fix cargo fmt issue
lquerel May 28, 2024
1277731
chore(just): Fix just file
lquerel May 28, 2024
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
183 changes: 149 additions & 34 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ anyhow = "1.0.83"
itertools = "0.12.1"
globset = { version = "0.4.14", features = ["serde1"] }
miette = { version = "7.2.0", features = ["fancy", "serde"] }
include_dir = "0.7.3"
tempdir = "0.3.7"

# Features definition =========================================================
[features]
Expand Down Expand Up @@ -69,10 +71,15 @@ serde.workspace = true
serde_yaml.workspace = true
serde_json.workspace = true
walkdir.workspace = true
include_dir.workspace = true
thiserror.workspace = true
miette.workspace = true

rayon = "1.10.0"

[dev-dependencies]
weaver_diff = { path = "crates/weaver_diff" }
tempdir.workspace = true
assert_cmd = "2.0.14"

[profile.release]
Expand Down
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ COPY crates /build/crates
COPY data /build/data
COPY src /build/src
COPY tests build/tests
COPY diagnostic_templates /build/diagnostic_templates
Copy link
Contributor Author

Choose a reason for hiding this comment

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

No longer needed as the default templates are now embedded into the app's binary.

COPY default_diagnostic_templates build/default_diagnostic_templates

# Don't build release, so we get template debugging output.
RUN cargo build

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
[![codecov](https://codecov.io/gh/open-telemetry/weaver/graph/badge.svg?token=tmWKFoMT2G)](https://codecov.io/gh/open-telemetry/weaver)
[![build](https://github.com/open-telemetry/weaver/actions/workflows/audit.yml/badge.svg)](https://github.com/open-telemetry/weaver/actions/workflows/audit.yml)
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Slack](https://img.shields.io/badge/Slack-OpenTelemetry_Weaver-purple)](https://cloud-native.slack.com/archives/C0697EXNTL3)
----

[Getting started](#getting-started) | [Main commands](#main-commands) | [Generate Doc & Code](crates/weaver_forge/README.md) | [Architecture](docs/architecture.md) | [Change log](CHANGELOG.md) | [Contributing](CONTRIBUTING.md) | [Links](#links) |
Expand Down Expand Up @@ -130,6 +131,7 @@ Telemetry Schemas.
## Documentation

- [Weaver Architecture](docs/architecture.md): A document detailing the architecture of the project.
- [Weaver Configuration](docs/weaver-config.md): A document detailing the configuration options available.
- [Weaver Forge](crates/weaver_forge/README.md): An integrated template engine designed to generate
documentation and code based on semantic conventions.
- [Weaver Checker](crates/weaver_policy_engine/README.md): An integrated policy
Expand Down
1 change: 1 addition & 0 deletions crates/weaver_cache/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ gix = { version = "0.63.0", default-features = false, features = [

thiserror.workspace = true
serde.workspace = true
miette.workspace = true

1 change: 1 addition & 0 deletions crates/weaver_cache/allowed-external-types.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
# the public API. Ideally this can have a few exceptions as possible.
allowed_external_types = [
"serde::ser::Serialize",
"miette::protocol::Diagnostic",
]
3 changes: 2 additions & 1 deletion crates/weaver_cache/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ use gix::clone::PrepareFetch;
use gix::create::Kind;
use gix::remote::fetch::Shallow;
use gix::{create, open, progress};
use miette::Diagnostic;
use serde::Serialize;
use tempdir::TempDir;

/// An error that can occur while creating or using a cache.
#[derive(thiserror::Error, Debug, Serialize)]
#[derive(thiserror::Error, Debug, Serialize, Diagnostic)]
#[non_exhaustive]
pub enum Error {
/// Home directory not found.
Expand Down
1 change: 1 addition & 0 deletions crates/weaver_checker/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0

#![allow(rustdoc::broken_intra_doc_links)]
#![doc = include_str!("../README.md")]

use std::fmt::{Display, Formatter};
Expand Down
9 changes: 5 additions & 4 deletions crates/weaver_codegen_test/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ use std::process::exit;
use weaver_cache::Cache;
use weaver_common::in_memory::LogMessage;
use weaver_common::{in_memory, Logger};
use weaver_forge::file_loader::FileSystemFileLoader;
use weaver_forge::registry::TemplateRegistry;
use weaver_forge::{GeneratorConfig, OutputDirective, TemplateEngine};
use weaver_forge::{OutputDirective, TemplateEngine};
use weaver_resolver::SchemaResolver;
use weaver_semconv::path::RegistryPath;
use weaver_semconv::registry::SemConvRegistry;

const SEMCONV_REGISTRY_PATH: &str = "./semconv_registry/";
const TEMPLATES_PATH: &str = "./templates/";
const TEMPLATES_PATH: &str = "./templates/registry/";
const REGISTRY_ID: &str = "test";
const TARGET: &str = "rust";

Expand All @@ -47,9 +48,9 @@ fn main() {
let schema = SchemaResolver::resolve_semantic_convention_registry(&mut registry)
.unwrap_or_else(|e| process_error(&logger, e));

let config = GeneratorConfig::new(TEMPLATES_PATH.into());
let engine = TemplateEngine::try_new(&format!("registry/{}", TARGET), config)
let loader = FileSystemFileLoader::try_new(TEMPLATES_PATH.into(), TARGET)
.unwrap_or_else(|e| process_error(&logger, e));
let engine = TemplateEngine::try_new(loader).unwrap_or_else(|e| process_error(&logger, e));
let template_registry = TemplateRegistry::try_from_resolved_registry(
schema
.registry(REGISTRY_ID)
Expand Down
8 changes: 8 additions & 0 deletions crates/weaver_common/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ impl DiagnosticMessages {
.iter()
.any(|message| message.diagnostic.severity == Some(Severity::Error))
}

/// Returns true if there are no diagnostic messages
#[must_use]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}

impl<T: WeaverDiagnostic + Diagnostic + Serialize + Send + Sync + 'static> From<T>
Expand Down Expand Up @@ -161,6 +167,8 @@ mod tests {
};
let diagnostic_messages = DiagnosticMessages::from_error(error.clone());
assert_eq!(diagnostic_messages.0.len(), 1);
assert!(diagnostic_messages.has_error());
assert!(!diagnostic_messages.is_empty());
assert_eq!(
diagnostic_messages.0[0].diagnostic.message,
"This is a test error"
Expand Down
1 change: 1 addition & 0 deletions crates/weaver_diff/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ edition.workspace = true
rust-version.workspace = true

[dependencies]
walkdir.workspace = true
similar = "2.5.0"


Expand Down
119 changes: 119 additions & 0 deletions crates/weaver_diff/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
//! This crate provides bare minimum support for colorized string differencing.

use similar::TextDiff;
use std::collections::HashSet;
use std::fs;
use std::path::Path;
use walkdir::WalkDir;

const GREEN: &str = "\x1b[32m";
const RED: &str = "\x1b[31m";
Expand Down Expand Up @@ -30,3 +34,118 @@
result.push_str(RESET);
result
}

/// Displays differences between two directories and returns whether they are identical.
/// The function will print differences to stderr.
#[allow(clippy::print_stderr)]
pub fn diff_dir<P: AsRef<Path>>(expected_dir: P, observed_dir: P) -> std::io::Result<bool> {
jsuereth marked this conversation as resolved.
Show resolved Hide resolved
let mut expected_files = HashSet::new();
let mut observed_files = HashSet::new();

// Walk through the first directory and add files to files1 set
for entry in WalkDir::new(&expected_dir)
.into_iter()

Check warning on line 47 in crates/weaver_diff/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/weaver_diff/src/lib.rs#L47

Added line #L47 was not covered by tests
.filter_map(|e| e.ok())
{
let path = entry.path();
if path.is_file() {
let relative_path = path
.strip_prefix(&expected_dir)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;

Check warning on line 54 in crates/weaver_diff/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/weaver_diff/src/lib.rs#L53-L54

Added lines #L53 - L54 were not covered by tests
_ = expected_files.insert(relative_path.to_path_buf());
}
}

// Walk through the second directory and add files to files2 set
for entry in WalkDir::new(&observed_dir)
.into_iter()

Check warning on line 61 in crates/weaver_diff/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/weaver_diff/src/lib.rs#L61

Added line #L61 was not covered by tests
.filter_map(|e| e.ok())
{
let path = entry.path();
if path.is_file() {
let relative_path = path
.strip_prefix(&observed_dir)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;

Check warning on line 68 in crates/weaver_diff/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/weaver_diff/src/lib.rs#L67-L68

Added lines #L67 - L68 were not covered by tests
_ = observed_files.insert(relative_path.to_path_buf());
}
}

// Assume directories are identical until proven otherwise
let mut are_identical = true;

// Compare files in both sets
for file in expected_files.intersection(&observed_files) {
let file1_content =
fs::read_to_string(expected_dir.as_ref().join(file))?.replace("\r\n", "\n");

Check warning on line 79 in crates/weaver_diff/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/weaver_diff/src/lib.rs#L79

Added line #L79 was not covered by tests
let file2_content =
fs::read_to_string(observed_dir.as_ref().join(file))?.replace("\r\n", "\n");

Check warning on line 81 in crates/weaver_diff/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/weaver_diff/src/lib.rs#L81

Added line #L81 was not covered by tests

if file1_content != file2_content {
are_identical = false;
eprintln!(
"Files {:?} and {:?} are different",
expected_dir.as_ref().join(file),
observed_dir.as_ref().join(file)

Check warning on line 88 in crates/weaver_diff/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/weaver_diff/src/lib.rs#L86-L88

Added lines #L86 - L88 were not covered by tests
);

eprintln!(
"Found differences:\n{}",
diff_output(&file1_content, &file2_content)

Check warning on line 93 in crates/weaver_diff/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/weaver_diff/src/lib.rs#L91-L93

Added lines #L91 - L93 were not covered by tests
);
break;

Check warning on line 95 in crates/weaver_diff/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/weaver_diff/src/lib.rs#L95

Added line #L95 was not covered by tests
}
}
// If any file is unique to one directory, they are not identical
let not_in_observed = expected_files
.difference(&observed_files)

Check warning on line 100 in crates/weaver_diff/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/weaver_diff/src/lib.rs#L100

Added line #L100 was not covered by tests
.collect::<Vec<_>>();
if !not_in_observed.is_empty() {
are_identical = false;
eprintln!("Observed output is missing files: {:?}", not_in_observed);

Check warning on line 104 in crates/weaver_diff/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/weaver_diff/src/lib.rs#L103-L104

Added lines #L103 - L104 were not covered by tests
}
let not_in_expected = observed_files
.difference(&expected_files)

Check warning on line 107 in crates/weaver_diff/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/weaver_diff/src/lib.rs#L107

Added line #L107 was not covered by tests
.collect::<Vec<_>>();
if !not_in_expected.is_empty() {
are_identical = false;
eprintln!(
"Observed output has unexpected files: {:?}",
not_in_expected

Check warning on line 113 in crates/weaver_diff/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/weaver_diff/src/lib.rs#L110-L113

Added lines #L110 - L113 were not covered by tests
);
}

Ok(are_identical)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_diff_output() {
let original = "Hello, world!";
let updated = "Hello, there!";
let diff = diff_output(original, updated);
assert_eq!(
diff,
"\u{1b}[31m- Hello, world!\n\u{1b}[32m+ Hello, there!\n\u{1b}[0m"
);
}

#[test]
fn test_diff_dir() {
let expected_dir = "./src";
let observed_dir = "./src";

let are_identical =
diff_dir(&expected_dir, &observed_dir).expect("Failed to diff directories");
assert!(are_identical);

let expected_dir = "./src";
let observed_dir = "../weaver_cache/src";

let are_identical =
diff_dir(&expected_dir, &observed_dir).expect("Failed to diff directories");
assert!(!are_identical);
}
}
9 changes: 8 additions & 1 deletion crates/weaver_forge/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,11 @@ serde_json.workspace = true
rayon.workspace = true
walkdir.workspace = true
globset.workspace = true
miette.workspace = true
miette.workspace = true
include_dir.workspace = true

[dev-dependencies]
opentelemetry = { version = "0.22.0", features = ["trace", "metrics", "logs", "otel_unstable"] }
opentelemetry_sdk = { version = "0.22.1", features = ["trace", "metrics", "logs"] }
opentelemetry-stdout = { version = "0.3.0", features = ["trace", "metrics", "logs"] }

Loading
Loading