Skip to content

feat: add environment metadata file sysand_env/env.toml#175

Open
victor-linroth-sensmetry wants to merge 13 commits intomainfrom
feat/resolved-manifest
Open

feat: add environment metadata file sysand_env/env.toml#175
victor-linroth-sensmetry wants to merge 13 commits intomainfrom
feat/resolved-manifest

Conversation

@victor-linroth-sensmetry
Copy link
Copy Markdown
Collaborator

@victor-linroth-sensmetry victor-linroth-sensmetry commented Feb 11, 2026

This PR adds a env.toml containing metadata for the projects installed in the local environment
(inluding editable projects not present inside the sysand_env folder).

Each project has the following fields:

  • publisher: String (optional).
    Publisher of the project. Intended for display purposes.
  • name: String (optional).
    Name of the project. Intended for display purposes.
  • version: String (required).
    Version of the project.
  • path: String (required).
    Path to the root directory of the project.
    If the project is not editable this should be relative
    to the env directory and otherwise it should be relative
    to the workspace root.
  • identifiers: Array of strings (required for non-editable projects)
    List of identifiers (IRIs) used for the project.
    The first identifier is to. be considered the canonical
    identifier, and if the project is not editable this
    is the IRI it is installed as. The rest are considered
    as aliases. Can only be empty for editable projects.
  • usages: Array of strings.
    Usages of the project. Intended for tools needing to
    track the interdependence of project in the environment.
  • editable: bool.
    Indicator of wether the project is fully installed in
    the environment or located elsewhere.
  • files: Array of strings (only for editable projects).
    In case of an editable project these are the files
    belonging to the project. Intended for tools that
    are not able to natively parse and understand the
    projects .meta.json file. Paths should be relative
    to the path of the project.
  • workspace: Indicator of wether the project is part of a workspace.

The current implementation doesn't change how projects.txt works and is intended to offer a transition step between env structures. The env.toml isn't directly managed by
LocalDirectoryEnvironment since such a thing will likely require a change in the
WriteEnvironment trait. In particular it would have to offer the ability to give alias identifiers in addition to the main IRI used for installation (since we want to communicate the dependency structure between projects we need all aliases as well, at least if we want to incrementally add or remove from the environment).

Also since the current implementation of workspaces only affects the build command, the workspace field isn't really effective at the moment, but should work as expected once the workspace feature catches up.

Example:

# This file is automatically generated by Sysand and is not intended to be edited manually.

version = "0.1"

[[project]]
name = "SYSMOD"
identifiers = [
    "urn:kpar:sysmod",
]
version = "5.0.0-alpha.2"
path = "a0aacee34dd4cd5e2d07ab43d5e30772ec86dbf3c8fafb033bad338dd7a0f02e/5.0.0-alpha.2.kpar"
usages = [
    "urn:kpar:analysis-library",
    "urn:kpar:cause-and-effect-library",
    "urn:kpar:data-type-library",
    "urn:kpar:function-library",
    "urn:kpar:geometry-library",
    "urn:kpar:metadata-library",
    "urn:kpar:quantities-and-units-library",
    "urn:kpar:requirement-derivation-library",
    "urn:kpar:semantic-library",
    "urn:kpar:systems-library",
]

[[project]]
name = "Testing"
version = "0.0.1"
path = "."
usages = [
    "urn:kpar:sysmod",
]
editable = true
files = [
    "test.sysml",
    "test.kerml",
]

@andrius-puksta-sensmetry
Copy link
Copy Markdown
Collaborator

Information provided (if available) includes

  • Publisher
  • Name
  • Directory/Files
  • Usages

What about IRIs for non-PURL usages? Since names will likely not be unique (e.g. 10 projects named "Requirements"), how will they be disambiguated to the user?

@victor-linroth-sensmetry
Copy link
Copy Markdown
Collaborator Author

What about IRIs for non-PURL usages? Since names will likely not be unique (e.g. 10 projects named "Requirements"), how will they be disambiguated to the user?

Well, our solution for name collisions is to use namespaces(/publishers). If you don't use them, then you don't get the solution.

@daumantas-kavolis-sensmetry
Copy link
Copy Markdown
Member

This is communicated through a "resolved manifest" current.toml

current.toml is very non-descriptive or sounds quite irrelevant to an environment. env.toml or projects.toml would be far clearer.

In particular this means paths are absolute

I highly suggest using paths relative to manifest/sysand_env for paths inside sysand_env and project folders as majority of the paths will have an identical prefix that can trivially be removed.

What about IRIs for non-PURL usages? Since names will likely not be unique (e.g. 10 projects named "Requirements"), how will they be disambiguated to the user?

Why would anyone care about collisions in what is effectively a display name? If a user has multiple projects named the same, they have bigger issues than some ambiguous name.

@daumantas-kavolis-sensmetry
Copy link
Copy Markdown
Member

Maybe also add workspace = [0, 1, ...] top-level property that controls workspace/project roots for analysis?

@consideRatio consideRatio changed the title Add a resolved manifest to sysand_env Add a resolved manifest sysand_env/current.toml Mar 13, 2026
@andrius-puksta-sensmetry andrius-puksta-sensmetry changed the title Add a resolved manifest sysand_env/current.toml dd a resolved manifest sysand_env/current.toml Mar 16, 2026
@andrius-puksta-sensmetry andrius-puksta-sensmetry changed the title dd a resolved manifest sysand_env/current.toml feat: add a resolved manifest sysand_env/current.toml Mar 16, 2026
@victor-linroth-sensmetry victor-linroth-sensmetry changed the title feat: add a resolved manifest sysand_env/current.toml feat: add environment metadata file sysand_env/env.toml Mar 20, 2026
@victor-linroth-sensmetry victor-linroth-sensmetry force-pushed the feat/resolved-manifest branch 8 times, most recently from 5f996f0 to ec6f714 Compare March 24, 2026 20:28
…t of the current project.

Signed-off-by: victor.linroth.sensmetry <victor.linroth@sensmetry.com>
Signed-off-by: victor.linroth.sensmetry <victor.linroth@sensmetry.com>
Signed-off-by: victor.linroth.sensmetry <victor.linroth@sensmetry.com>
Signed-off-by: victor.linroth.sensmetry <victor.linroth@sensmetry.com>
Signed-off-by: victor.linroth.sensmetry <victor.linroth@sensmetry.com>
Signed-off-by: victor.linroth.sensmetry <victor.linroth@sensmetry.com>
Signed-off-by: victor.linroth.sensmetry <victor.linroth@sensmetry.com>
Signed-off-by: victor.linroth.sensmetry <victor.linroth@sensmetry.com>
Signed-off-by: victor.linroth.sensmetry <victor.linroth@sensmetry.com>
Signed-off-by: victor.linroth.sensmetry <victor.linroth@sensmetry.com>
Signed-off-by: victor.linroth.sensmetry <victor.linroth@sensmetry.com>
@victor-linroth-sensmetry victor-linroth-sensmetry marked this pull request as ready for review March 25, 2026 07:43
#[serde(deserialize_with = "deserialize_unix_path")]
pub path: Utf8UnixPathBuf,
/// List of identifiers (IRIs) used for the project.
/// The first identifier is to. be considered the canonical
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
/// The first identifier is to. be considered the canonical
/// The first identifier is considered the canonical

/// to the `path` of the project.
#[serde(deserialize_with = "deserialize_optional_unix_paths", default)]
pub files: Option<Vec<Utf8UnixPathBuf>>,
/// Indicator of wether the project is part of a workspace.
Copy link
Copy Markdown
Collaborator

@andrius-puksta-sensmetry andrius-puksta-sensmetry Mar 25, 2026

Choose a reason for hiding this comment

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

Suggested change
/// Indicator of wether the project is part of a workspace.
/// Indicator of whether the project is part of current workspace.

@andrius-puksta-sensmetry
Copy link
Copy Markdown
Collaborator

files: Array of strings (only for editable projects).
In case of an editable project these are the files
belonging to the project. Intended for tools that
are not able to natively parse and understand the
projects .meta.json file. Paths should be relative
to the path of the project.

Since editable projects are expected to change frequently, how will
new/removed files be handled?

workspace: Indicator of wether the project is part of a workspace.

Which workspace? Workspace that owns this env? Or another unrelated one?

.as_os_str()
.to_str()
// This conversion should always be possible since everything is UTF8 encoded
.expect("component of `Utf8Path` no convertible to `str`"),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
.expect("component of `Utf8Path` no convertible to `str`"),
.expect("component of `Utf8Path` not convertible to `str`"),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nevermind, just use component.as_str() directly.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes, looking at it the str conversion is probably leftover code from before camino. Will fix.

@victor-linroth-sensmetry
Copy link
Copy Markdown
Collaborator Author

Since editable projects are expected to change frequently, how will new/removed files be handled?

Hmm, good question. Could maybe be updated whenever the env is updated. Or simply simply drop files and say tools will need to parse the .meta.json if they want exact files. I've been leaning towards that before.

Which workspace? Workspace that owns this env? Or another unrelated one?

Yeah, I think the idea at least is to have common lockfile, env and build directory in a workspace. This is to indicate of that is the case and which projects are workspace memebers.

@andrius-puksta-sensmetry
Copy link
Copy Markdown
Collaborator

Since editable projects are expected to change frequently, how will new/removed files be handled?

Hmm, good question. Could maybe be updated whenever the env is updated. Or simply simply drop files and say tools will need to parse the .meta.json if they want exact files. I've been leaning towards that before.

Agree on dropping files. It's not env responsibility to precisely keep track of projects outside of it.

Which workspace? Workspace that owns this env? Or another unrelated one?

Yeah, I think the idea at least is to have common lockfile, env and build directory in a workspace. This is to indicate of that is the case and which projects are workspace memebers.

Ok, so current workspace. Yeah, having common env/lockfile/build dir is a sensible thing to do.

core/src/lock.rs Outdated
Comment on lines +488 to +493
// Simple stopgap solution for now
pub fn get_package_url<'a>(&self) -> Option<PackageUrl<'a>> {
self.identifiers
.first()
.and_then(|id| PackageUrl::from_str(id.as_str()).ok())
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Shouldn't this use publisher and name (if both are present)?

Copy link
Copy Markdown
Collaborator

@andrius-puksta-sensmetry andrius-puksta-sensmetry Mar 25, 2026

Choose a reason for hiding this comment

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

Especially with my upcoming changes to usage specification, not sure if identifiers will contain the PURL (haven't decided yet).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Leftover from before publisher was added. Should probably remove.

Comment on lines +95 to +96
// TODO: Consider under which circumstances (if any)
// the workspace should carry over.
Copy link
Copy Markdown
Collaborator

@andrius-puksta-sensmetry andrius-puksta-sensmetry Mar 25, 2026

Choose a reason for hiding this comment

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

Workspace should not carry over by default, as that's unlikely to be the goal of the user when cloning a project. It would be sufficient to maybe expose command to add current project to workspace (out of scope of this PR), but not sure if it's worth it, workspace file can be easily edited manually.

Comment on lines +75 to +81
let root_path = if let Some(current_workspace) = &ctx.current_workspace {
wrapfs::canonicalize(current_workspace.root_path())?
} else if let Some(current_project) = &ctx.current_project {
wrapfs::canonicalize(current_project.root_path())?
} else {
wrapfs::canonicalize(&ctx.current_directory)?
};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

These should already be canonical and if not, should be made so elsewhere, as we need them to be canonical in most places. Regarding Windows, probably a good idea to use dunce crate to avoid UNC where possible.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, this was due to Windows and UNC nonsense. canonicalize and current_dir gives different formats for some reason.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

From what I found, CWD is generally never UNC on Windows.

@andrius-puksta-sensmetry
Copy link
Copy Markdown
Collaborator

The env.toml isn't directly managed by
LocalDirectoryEnvironment since such a thing will likely require a change in the
WriteEnvironment trait. In particular it would have to offer the ability to give alias identifiers in addition to the main IRI used for installation (since we want to communicate the dependency structure between projects we need all aliases as well, at least if we want to incrementally add or remove from the environment).

Add a TODO to this effect somewhere. Not sure what to do about this longer term, as env.toml also includes editable projects, which are not installed into the environment per se, and also the current project(s)... WriteEnvironment then would have to be somehow coupled with current workspace/projects, not sure how to go about that.

Signed-off-by: victor.linroth.sensmetry <victor.linroth@sensmetry.com>
Signed-off-by: victor.linroth.sensmetry <victor.linroth@sensmetry.com>
@victor-linroth-sensmetry
Copy link
Copy Markdown
Collaborator Author

Add a TODO to this effect somewhere. Not sure what to do about this longer term, as env.toml also includes editable projects, which are not installed into the environment per se, and also the current project(s)... WriteEnvironment then would have to be somehow coupled with current workspace/projects, not sure how to go about that.

Put a TODO in command_sync as that's the main point of generating env.toml.

#[derive(Debug, Deserialize)]
pub struct EnvMetadata {
pub version: String,
#[serde(rename = "project", skip_serializing_if = "Vec::is_empty", default)]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No need for these here, as the serialization is implemented manually. Same applies to Lock (maybe there are others?).

/// identifier, and if the project is not `editable` this
/// is the IRI it is installed as. The rest are considered
/// as aliases. Can only be empty for `editable` projects.
#[serde(skip_serializing_if = "Vec::is_empty", default)]
Copy link
Copy Markdown
Collaborator

@andrius-puksta-sensmetry andrius-puksta-sensmetry Mar 30, 2026

Choose a reason for hiding this comment

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

No need for this, see above.

(same applies to other fields here)

Comment on lines +272 to +296
pub fn to_toml(&self) -> Table {
let mut table = Table::new();
if let Some(publisher) = &self.publisher {
table.insert("publisher", value(publisher));
}
if let Some(name) = &self.name {
table.insert("name", value(name));
}
table.insert("version", value(&self.version));
table.insert("path", value(self.path.as_str()));
if !self.identifiers.is_empty() {
table.insert(
"identifiers",
value(multiline_array(self.identifiers.iter())),
);
}
if !self.usages.is_empty() {
table.insert("usages", value(multiline_array(self.usages.iter())));
}
if self.editable {
table.insert("editable", value(true));
}

table
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

workspace is ignored

/// Adds identifiers from other project.
/// Should only be done if the underlying projects are the same.
/// In particular they must have the same version.
pub fn merge(&mut self, other: &EnvProject) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
pub fn merge(&mut self, other: &EnvProject) {
pub fn merge_identifiers(&mut self, other: &EnvProject) {

Comment on lines +224 to +227
dunce::canonicalize(path.as_ref())
.map(|path| {
Utf8PathBuf::from_path_buf(path)
.expect("expected Dunce not to introduce non UTF8 characters")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This may not be the case with symlinks/relative path inputs. Do a manual match and return ErrorKind::InvalidData if conversion fails, like camino does.

Comment on lines 38 to 40
pub fn command_env<P: AsRef<Utf8Path>>(path: P) -> Result<LocalDirectoryEnvironment> {
Ok(do_env_local_dir(path)?)
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This doesn't seem to create env.toml, which is later relied upon to exist in add_single_env_project. Am I missing something?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants