Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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 Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/weaver_common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ once_cell.workspace = true
schemars.workspace = true
ureq.workspace = true
log.workspace = true
url.workspace = true

tempfile.workspace = true
dirs = "6.0.0"
Expand Down
34 changes: 34 additions & 0 deletions crates/weaver_common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use miette::Diagnostic;
use paris::formatter::colorize_string;
use serde::Serialize;
use std::io::Write;
use std::path::Path;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};

Expand Down Expand Up @@ -295,3 +296,36 @@ pub fn warn_flare<T: std::fmt::Display>(message: T) -> String {
pub fn log_warn<T: std::fmt::Display>(message: T) {
log::warn!("{}", warn_flare(message));
}

/// Types of path strings we can support.
pub enum PathType {
/// A URL path, like http://server/
URL,
/// A relative path, like ../some-file
RelativePath,
/// An absolute path, like /my/file/location
AbsolutePath,
/// Weaver-special. A reference to a file
/// in a git repo or other.
WeaverPath,
}

/// Returns the type of path we're dealing with.
#[must_use]
pub fn get_path_type(input: &str) -> PathType {
match url::Url::parse(input) {
Ok(_) => PathType::URL,
Err(url::ParseError::RelativeUrlWithoutBase) => {
let test_path = Path::new(input);
if test_path.is_absolute() {
PathType::AbsolutePath
} else {
PathType::RelativePath
}
}
// TODO - we can learn more from error, we may be able
// to determine if this is a git-relative path or
// in-archive file reference.
Err(_) => PathType::WeaverPath,
}
}
58 changes: 57 additions & 1 deletion crates/weaver_common/src/vdir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,56 @@
},
}

impl VirtualDirectoryPath {
/// Converts a virtual directory path by manipulating the "sub folder".
///
/// Returning an empty string means no sub_folder will be used in resulting path.
///
/// Sub folder will be modified as follows:
///
/// - LocalFolder: will see the entire path
/// - others: will see the path inside the archive or empty string if none.
pub fn map_sub_folder<F: FnOnce(String) -> String>(self, f: F) -> VirtualDirectoryPath {
match self {
LocalFolder { path } => LocalFolder { path: f(path) },
LocalArchive { path, sub_folder } => LocalArchive {
path,
sub_folder: {
let result = f(sub_folder.unwrap_or("".to_string()));
if result.is_empty() {
None
} else {
Some(result)
}
}
},
RemoteArchive { url, sub_folder } => RemoteArchive {
url,
sub_folder: {
let result = f(sub_folder.unwrap_or("".to_string()));
if result.is_empty() {
None
} else {
Some(result)
}
}
},
GitRepo { url, refspec, sub_folder } => GitRepo {
url,
refspec,
sub_folder: {
let result = f(sub_folder.unwrap_or("".to_string()));
if result.is_empty() {
None
} else {
Some(result)
}
}
},
}
}
}

/// Enables parsing a [`VirtualDirectoryPath`] from a string representation.
///
/// This implementation allows easy deserialization from strings (e.g. configuration files, command-line arguments).
Expand Down Expand Up @@ -686,10 +736,16 @@

/// Returns the original string representation that was used to create this `VirtualDirectory`.
#[must_use]
pub fn vdir_path(&self) -> &str {
pub fn vdir_path_str(&self) -> &str {
&self.vdir_path
}

/// Returns the original `VirtualDirectoryRef` that was used to create this `VirtualDirectory`.
#[must_use]
pub fn vdir_path(&self) -> VirtualDirectoryPath {
self.vdir_path_str().try_into().expect("VirtualDirectory should not have invalid `vdir_path`.")
}

/// Creates and returns a new temporary directory within `.weaver/vdir_cache`.
///
/// The created directory and its contents are automatically deleted when dropped.
Expand Down
6 changes: 5 additions & 1 deletion crates/weaver_semconv/src/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ pub struct RegistryManifest {
pub struct Dependency {
/// The name of the dependency.
pub name: String,
/// The registry path of the dependency.
/// The path to the dependency.
///
/// This can be either:
/// - A manifest of a published registry
/// - A directory containing the raw definition.
pub registry_path: VirtualDirectoryPath,
Copy link
Member

Choose a reason for hiding this comment

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

can we call it accordingly? could be confusing to see registry_path: http://otel.io/schemas ...

Suggested change
pub registry_path: VirtualDirectoryPath,
pub registry_location: VirtualDirectoryPath,

or

Suggested change
pub registry_path: VirtualDirectoryPath,
pub registry: VirtualDirectoryPath,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since manifest work today and folks use them, I didn't want to issue breaking changes.

I'm happy to move to something else and declare an alias here so we don't break.

Personally, I prefer registry_uri or registry_location better. The key thing to denote is this is a "virtual directory path" in Weaver vernacular, so it can point at directories inside a git repository or zip archive.

Should I update that now?

Copy link
Member

Choose a reason for hiding this comment

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

now is great, I can also do it in #1106 (registry_uri sounds good and we'd align registy_url with it)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since this is a rather large PR - I'd rather do a dedicate PR for that change.

I think we could also look at moving from registry_manifest.yaml -> manifest.yaml in that one.

}

Expand Down
80 changes: 75 additions & 5 deletions crates/weaver_semconv/src/registry_repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,19 @@ use std::sync::Arc;

use crate::manifest::RegistryManifest;
use crate::Error;
use weaver_common::log_info;
use weaver_common::vdir::{VirtualDirectory, VirtualDirectoryPath};
use weaver_common::{get_path_type, log_info};

/// The name of the registry manifest file.
pub const REGISTRY_MANIFEST: &str = "registry_manifest.yaml";

/// A semantic convention registry repository that can be:
/// - A simple wrapper around a local directory
/// - Initialized from a Git repository
/// - Initialized from a Git archive
/// - A definition repository, which is one of:
/// - A simple wrapper around a local directory
/// - Initialized from a Git repository
/// - Initialized from a Git archive
/// - A published repository, which is a manifest file
/// that denotes where to find aspects of the registry.
#[derive(Default, Debug, Clone)]
pub struct RegistryRepo {
// A unique identifier for the registry (e.g. main, baseline, etc.)
Expand Down Expand Up @@ -66,7 +69,7 @@ impl RegistryRepo {
/// Returns the registry path textual representation.
#[must_use]
pub fn registry_path_repr(&self) -> &str {
self.registry.vdir_path()
self.registry.vdir_path_str()
}

/// Returns the registry manifest specified in the registry repo.
Expand All @@ -75,9 +78,37 @@ impl RegistryRepo {
self.manifest.as_ref()
}

/// Returns the resolved schema URL, if available in the manifest.
#[must_use]
pub fn resolved_schema_url(&self) -> Option<VirtualDirectoryPath> {
let manifest = self.manifest.as_ref()?;
let resolved_url: &str = manifest.resolved_schema_url.as_ref()?;
match get_path_type(resolved_url) {
weaver_common::PathType::RelativePath => {
let vdir_was_manifest_file = self.manifest_path()?.is_file();
Some(self.registry.vdir_path().map_sub_folder(|path| {
if vdir_was_manifest_file {
match Path::new(&path).parent() {
Some(parent) => format!("{}", parent.join(resolved_url).display()),
None => format!(""),
}
} else {
format!("{}", Path::new(&path).join(resolved_url).display())
}
}))
}
_ => resolved_url.try_into().ok(),
}
}

/// Returns the path to the `registry_manifest.yaml` file (if any).
#[must_use]
pub fn manifest_path(&self) -> Option<PathBuf> {
// First check to see if we're pointing at a manifest.
if self.registry.path().is_file() {
// The VirtualDirectory *is* the registry.
return Some(self.registry.path().to_path_buf());
}
let manifest_path = self.registry.path().join(REGISTRY_MANIFEST);
if manifest_path.exists() {
log_info(format!(
Expand Down Expand Up @@ -127,4 +158,43 @@ mod tests {
// The local folder should not be deleted.
assert!(repo_path.exists());
}

#[test]
fn test_resolved_registry_path() {
// A RegistryRepo created from a local folder.
let registry_path = VirtualDirectoryPath::LocalFolder {
path: "tests/published_repository/resolved/1.0.0".to_owned(),
};
let repo =
RegistryRepo::try_new("main", &registry_path).expect("Failed to load test repository.");
let Some(manifest) = repo.manifest() else {
panic!("Did not resolve manifest for repo: {repo:?}");
};
assert_eq!(manifest.name, "resolved");

let Some(resolved_path) = repo.resolved_schema_url() else {
panic!(
"Should find a resolved schema path from manfiest in {}",
repo.registry_path_repr()
);
};
assert_eq!(
"tests/published_repository/resolved/resolved_1.0.0.yaml",
format!("{resolved_path}")
);

// Now make sure a different repository with full URL works too.
let registry_path = VirtualDirectoryPath::LocalFolder {
path: "tests/published_repository/resolved/2.0.0".to_owned(),
};
let repo =
RegistryRepo::try_new("main", &registry_path).expect("Failed to load test repository.");
let Some(resolved_path) = repo.resolved_schema_url() else {
panic!(
"Should find a resolved schema path from manfiest in {}",
repo.registry_path_repr()
);
};
assert_eq!("https://github.com/open-telemetry/weaver.git\\creates/weaver_semconv/tests/published_respository/resolved/resolved_2.0.0", format!("{resolved_path}"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
file_format: manifest/2.0.0
name: resolved
description: Test repository that has been resolved.
version: 1.0.0
repository_url: https://github.com/open-telemetry/weaver.git
stability: stable
resolved_schema_url: resolved_1.0.0.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
file_format: manifest/2.0.0
name: resolved
description: Test repository that has been resolved.
version: 2.0.0
repository_url: https://github.com/open-telemetry/weaver.git
stability: stable
resolved_schema_url: https://github.com/open-telemetry/weaver.git\creates/weaver_semconv/tests/published_respository/resolved/resolved_2.0.0
Loading