schema helpers CHANGE added LYS_MOD_IMPORTED_REV
The new ::lys_get_module_without_revision() modifies the behavior of
the ::lys_parse_load() when a module is imported without specifying a
revision. Such an imported module is marked with the
::LYS_MOD_IMPORTED_REV flag and its priority is the highest. Also, the
implemented module takes precedence over the module with the latest
revision.
diff --git a/src/context.h b/src/context.h
index bf6c3ef..029f513 100644
--- a/src/context.h
+++ b/src/context.h
@@ -73,8 +73,7 @@
* For a context, the first time the latest revision of a module is requested, it is properly searched for and loaded.
* However, when this module is requested (without revision) the second time, the one found previously is returned.
* This has the advantage of not searching for the module repeatedly but there is a drawback in case the content of search
- * directories is updated and a later revision become available. However, to force libyang to re-search the
- * latest revision, ::ly_ctx_reset_latests() can be used (note that it applies to all the modules in the context).
+ * directories is updated and a later revision become available.
*
* Context holds all the schema modules internally. To get a specific module, use ::ly_ctx_get_module() (or some of its
* variants). If you need to do something with all the modules in the context, it is advised to iterate over them using
@@ -530,6 +529,8 @@
/**
* @brief Reset cached latest revision information of the schemas in the context.
*
+ * This function is deprecated and should not be used.
+ *
* When a (sub)module is imported/included without revision, the latest revision is
* searched. libyang searches for the latest revision in searchdirs and/or via provided
* import callback ::ly_module_imp_clb() just once. Then it is expected that the content
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 2a399cd..66c42a4 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -1191,6 +1191,14 @@
imp = &pmod->imports[u];
if (!imp->module) {
LY_CHECK_RET(lys_parse_load(PARSER_CTX(pctx), imp->name, imp->rev[0] ? imp->rev : NULL, new_mods, &imp->module));
+
+ if (!imp->rev[0]) {
+ /* This module must be selected for the next similar
+ * import without revision-date to avoid incorrect
+ * derived identities in the ::lys_module.identities.
+ */
+ imp->module->latest_revision |= LYS_MOD_IMPORTED_REV;
+ }
}
/* check for importing the same module twice */
for (v = 0; v < u; ++v) {
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 3282db3..2d1f989 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -2333,6 +2333,8 @@
*/
#define LYS_MOD_LATEST_REV 0x01 /**< This is the latest revision of the module in the current context. */
#define LYS_MOD_LATEST_SEARCHDIRS 0x02 /**< This is the latest revision of the module found in searchdirs. */
+#define LYS_MOD_IMPORTED_REV 0x04 /**< This is the module revision used when importing the module without an explicit revision-date.
+ It is used for all such imports regardless of any changes made in the context. */
/** @} latestrevflags */
/**
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 5415c28..0dbfefa 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -861,6 +861,53 @@
}
/**
+ * @brief Get module without revision according to priorities.
+ *
+ * 1. Search for the module with LYS_MOD_IMPORTED_REV.
+ * 2. Search for the implemented module.
+ * 3. Search for the latest module in the context.
+ *
+ * @param[in] ctx libyang context where module is searched.
+ * @param[in] name Name of the searched module.
+ * @param[out] keep_search Flag set to 1 if searchpaths or module
+ * callback must be searched to obtain latest available revision.
+ * @return Found module from context or NULL.
+ */
+static struct lys_module *
+lys_get_module_without_revision(struct ly_ctx *ctx, const char *name, ly_bool *keep_search)
+{
+ struct lys_module *mod, *mod_impl;
+ uint32_t index;
+
+ *keep_search = 0;
+
+ /* Try to find module with LYS_MOD_IMPORTED_REV flag. */
+ index = 0;
+ while ((mod = ly_ctx_get_module_iter(ctx, &index))) {
+ if (!strcmp(mod->name, name) && (mod->latest_revision & LYS_MOD_IMPORTED_REV)) {
+ break;
+ }
+ }
+
+ /* Try to find the implemented module. */
+ mod_impl = ly_ctx_get_module_implemented(ctx, name);
+ if (mod && mod_impl) {
+ LOGVRB("Implemented module \"%s@%s\" is not used for import, "
+ "revision \"%s\" is imported instead.",
+ mod_impl->name, mod_impl->revision, mod->revision);
+ return mod;
+ } else if (mod_impl) {
+ return mod_impl;
+ }
+
+ /* Try to find the latest module in the current context. */
+ mod = ly_ctx_get_module_latest(ctx, name);
+ *keep_search = 1;
+
+ return mod;
+}
+
+/**
* @brief Check if a circular dependency exists between modules.
*
* @param[in] ctx libyang context for log an error.
@@ -885,6 +932,7 @@
lys_parse_load(struct ly_ctx *ctx, const char *name, const char *revision, struct ly_set *new_mods,
struct lys_module **mod)
{
+ ly_bool keep_search;
struct lys_module *mod_latest = NULL;
assert(mod && new_mods);
@@ -897,8 +945,8 @@
*mod = ly_ctx_get_module(ctx, name, revision);
} else {
/* Get the requested module of the latest revision in the context. */
- *mod = ly_ctx_get_module_latest(ctx, name);
- if (*mod) {
+ *mod = lys_get_module_without_revision(ctx, name, &keep_search);
+ if (keep_search) {
/* Let us now search with callback and searchpaths to check
* if there is newer revision outside the context.
*/