summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS4
-rw-r--r--lilv/lilv.h6
-rw-r--r--src/lilv_internal.h5
-rw-r--r--src/world.c103
-rw-r--r--test/lilv_test.c71
5 files changed, 142 insertions, 47 deletions
diff --git a/NEWS b/NEWS
index 0d3bf6a..b781ce8 100644
--- a/NEWS
+++ b/NEWS
@@ -1,10 +1,12 @@
lilv (0.22.1) unstable;
+ * Unload contained resources when bundle is unloaded
+ * Support re-loading plugins
* Fix Python bindings
* Fix documentation installation
* Fix outdated comment references to lilv_uri_to_path()
- -- David Robillard <d@drobilla.net> Wed, 28 Oct 2015 14:31:05 -0400
+ -- David Robillard <d@drobilla.net> Thu, 29 Oct 2015 00:23:04 -0400
lilv (0.22.0) stable;
diff --git a/lilv/lilv.h b/lilv/lilv.h
index 6bced5e..feb8a0b 100644
--- a/lilv/lilv.h
+++ b/lilv/lilv.h
@@ -577,8 +577,8 @@ lilv_world_load_all(LilvWorld* world);
other things) MUST be identified by URIs (not paths) in save files.
*/
LILV_API void
-lilv_world_load_bundle(LilvWorld* world,
- LilvNode* bundle_uri);
+lilv_world_load_bundle(LilvWorld* world,
+ const LilvNode* bundle_uri);
/**
Load all specifications from currently loaded bundles.
@@ -609,7 +609,7 @@ lilv_world_load_plugin_classes(LilvWorld* world);
separately unloaded with lilv_world_unload_resource().
*/
LILV_API int
-lilv_world_unload_bundle(LilvWorld* world, LilvNode* bundle_uri);
+lilv_world_unload_bundle(LilvWorld* world, const LilvNode* bundle_uri);
/**
Load all the data associated with the given `resource`.
diff --git a/src/lilv_internal.h b/src/lilv_internal.h
index 15b00dc..89ae629 100644
--- a/src/lilv_internal.h
+++ b/src/lilv_internal.h
@@ -1,5 +1,5 @@
/*
- Copyright 2007-2014 David Robillard <http://drobilla.net>
+ Copyright 2007-2015 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -282,7 +282,8 @@ LilvScalePoints* lilv_scale_points_new(void);
LilvPluginClasses* lilv_plugin_classes_new(void);
LilvUIs* lilv_uis_new(void);
-LilvNode* lilv_world_get_manifest_uri(LilvWorld* world, LilvNode* bundle_uri);
+LilvNode* lilv_world_get_manifest_uri(LilvWorld* world,
+ const LilvNode* bundle_uri);
const uint8_t* lilv_world_blank_node_prefix(LilvWorld* world);
diff --git a/src/world.c b/src/world.c
index 02dbeec..ad98559 100644
--- a/src/world.c
+++ b/src/world.c
@@ -1,5 +1,5 @@
/*
- Copyright 2007-2014 David Robillard <http://drobilla.net>
+ Copyright 2007-2015 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -371,38 +371,51 @@ lilv_world_add_spec(LilvWorld* world,
}
static void
-lilv_world_add_plugin(LilvWorld* world,
- const SordNode* plugin_node,
- const LilvNode* manifest_uri,
- void* dynmanifest,
- const SordNode* bundle_node)
-{
- LilvNode* plugin_uri = lilv_node_new_from_node(world, plugin_node);
-
- const LilvPlugin* last = lilv_plugins_get_by_uri(world->plugins,
- plugin_uri);
- if (last) {
- LILV_ERRORF("Duplicate plugin <%s>\n", lilv_node_as_uri(plugin_uri));
- LILV_ERRORF("... found in %s\n", lilv_node_as_string(
- lilv_plugin_get_bundle_uri(last)));
- LILV_ERRORF("... and %s\n", sord_node_get_string(bundle_node));
- lilv_node_free(plugin_uri);
- return;
- }
+lilv_world_add_plugin(LilvWorld* world,
+ const SordNode* plugin_node,
+ const LilvNode* manifest_uri,
+ void* dynmanifest,
+ const SordNode* bundle)
+{
+ LilvNode* plugin_uri = lilv_node_new_from_node(world, plugin_node);
+ LilvPlugin* plugin = (LilvPlugin*)lilv_plugins_get_by_uri(
+ world->plugins, plugin_uri);
+
+ if (plugin) {
+ // Existing plugin, if this is different bundle, ignore it
+ // (use the first plug found in LV2_PATH)
+ const LilvNode* last_bundle = lilv_plugin_get_bundle_uri(plugin);
+ const char* plugin_uri_str = lilv_node_as_uri(plugin_uri);
+ if (sord_node_equals(bundle, last_bundle->node)) {
+ LILV_WARNF("Reloading plugin <%s>\n", plugin_uri_str);
+ plugin->loaded = false;
+ lilv_node_free(plugin_uri);
+ } else {
+ LILV_ERRORF("Duplicate plugin <%s>\n", plugin_uri_str);
+ LILV_ERRORF("... found in %s\n", lilv_node_as_string(last_bundle));
+ LILV_ERRORF("... and %s\n", sord_node_get_string(bundle));
+ lilv_node_free(plugin_uri);
+ return;
+ }
+ } else {
+ // Add new plugin to the world
+ plugin = lilv_plugin_new(
+ world, plugin_uri, lilv_node_new_from_node(world, bundle));
- // Create LilvPlugin
- LilvNode* bundle_uri = lilv_node_new_from_node(world, bundle_node);
- LilvPlugin* plugin = lilv_plugin_new(world, plugin_uri, bundle_uri);
+ // Add manifest as plugin data file (as if it were rdfs:seeAlso)
+ zix_tree_insert((ZixTree*)plugin->data_uris,
+ lilv_node_duplicate(manifest_uri),
+ NULL);
+
+ // Add plugin to world plugin sequence
+ zix_tree_insert((ZixTree*)world->plugins, plugin, NULL);
+ }
- // Add manifest as plugin data file (as if it were rdfs:seeAlso)
- zix_tree_insert((ZixTree*)plugin->data_uris,
- lilv_node_duplicate(manifest_uri),
- NULL);
#ifdef LILV_DYN_MANIFEST
// Set dynamic manifest library URI, if applicable
if (dynmanifest) {
- plugin->dynmanifest = (LilvDynManifest*)dynmanifest;
+ plug->dynmanifest = (LilvDynManifest*)dynmanifest;
++((LilvDynManifest*)dynmanifest)->refs;
}
#endif
@@ -420,9 +433,6 @@ lilv_world_add_plugin(LilvWorld* world,
NULL);
}
sord_iter_free(files);
-
- // Add plugin to world plugin sequence
- zix_tree_insert((ZixTree*)world->plugins, plugin, NULL);
}
SerdStatus
@@ -570,7 +580,7 @@ lilv_world_load_dyn_manifest(LilvWorld* world,
}
LilvNode*
-lilv_world_get_manifest_uri(LilvWorld* world, LilvNode* bundle_uri)
+lilv_world_get_manifest_uri(LilvWorld* world, const LilvNode* bundle_uri)
{
SerdNode manifest_uri = lilv_new_uri_relative_to_base(
(const uint8_t*)"manifest.ttl",
@@ -581,7 +591,7 @@ lilv_world_get_manifest_uri(LilvWorld* world, LilvNode* bundle_uri)
}
LILV_API void
-lilv_world_load_bundle(LilvWorld* world, LilvNode* bundle_uri)
+lilv_world_load_bundle(LilvWorld* world, const LilvNode* bundle_uri)
{
if (!lilv_node_is_uri(bundle_uri)) {
LILV_ERRORF("Bundle URI `%s' is not a URI\n",
@@ -633,7 +643,7 @@ lilv_world_load_bundle(LilvWorld* world, LilvNode* bundle_uri)
}
static int
-lilv_world_drop_graph(LilvWorld* world, LilvNode* graph)
+lilv_world_drop_graph(LilvWorld* world, const LilvNode* graph)
{
SordIter* i = sord_search(world->model, NULL, NULL, NULL, graph->node);
while (!sord_iter_end(i)) {
@@ -651,7 +661,7 @@ lilv_world_drop_graph(LilvWorld* world, LilvNode* graph)
/** Remove loaded_files entry so file will be reloaded if requested. */
static int
-lilv_world_unload_file(LilvWorld* world, LilvNode* file)
+lilv_world_unload_file(LilvWorld* world, const LilvNode* file)
{
ZixTreeIter* iter;
if (!zix_tree_find((ZixTree*)world->loaded_files, file, &iter)) {
@@ -662,16 +672,31 @@ lilv_world_unload_file(LilvWorld* world, LilvNode* file)
}
LILV_API int
-lilv_world_unload_bundle(LilvWorld* world, LilvNode* bundle_uri)
+lilv_world_unload_bundle(LilvWorld* world, const LilvNode* bundle_uri)
{
if (!bundle_uri) {
return 0;
}
- // Remove loaded_files entry for manifest.ttl
- LilvNode* manifest = lilv_world_get_manifest_uri(world, bundle_uri);
- lilv_world_unload_file(world, manifest);
- lilv_node_free(manifest);
+ // Unload any files, including manifest.ttl
+ LilvNodes* files = lilv_nodes_new();
+ LILV_FOREACH(nodes, i, world->loaded_files) {
+ const LilvNode* file = lilv_nodes_get(world->loaded_files, i);
+ if (!strncmp(lilv_node_as_string(file),
+ lilv_node_as_string(bundle_uri),
+ strlen(lilv_node_as_string(bundle_uri)))) {
+ zix_tree_insert((ZixTree*)files,
+ lilv_node_duplicate(file),
+ NULL);
+ }
+ }
+
+ LILV_FOREACH(nodes, i, files) {
+ const LilvNode* file = lilv_nodes_get(world->plugins, i);
+ lilv_world_unload_file(world, file);
+ }
+
+ lilv_nodes_free(files);
// Drop everything in bundle graph
return lilv_world_drop_graph(world, bundle_uri);
diff --git a/test/lilv_test.c b/test/lilv_test.c
index f179d33..7b6d14a 100644
--- a/test/lilv_test.c
+++ b/test/lilv_test.c
@@ -159,9 +159,9 @@ cleanup(void)
#define TEST_ASSERT(check) do {\
test_count++;\
if (!(check)) {\
- assert(false);\
error_count++;\
- fprintf(stderr, "lilv_test.c:%d: error: %s\n", __LINE__, #check);\
+ fprintf(stderr, "lilv_test.c:%d: error: test `%s' failed\n", __LINE__, #check);\
+ assert(check);\
}\
} while (0)
@@ -1940,6 +1940,72 @@ test_world(void)
/*****************************************************************************/
+static int
+test_reload_bundle(void)
+{
+ // Create a simple plugin bundle
+ create_bundle(MANIFEST_PREFIXES
+ ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
+ BUNDLE_PREFIXES
+ ":plug a lv2:Plugin ; "
+ PLUGIN_NAME("First name") " .");
+
+ if (!init_world()) {
+ return 0;
+ }
+
+ init_uris();
+ lilv_world_load_specifications(world);
+
+ // Load bundle
+ LilvNode* bundle_uri = lilv_new_uri(world, bundle_dir_uri);
+ lilv_world_load_bundle(world, bundle_uri);
+
+ // Check that plugin is present
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
+ TEST_ASSERT(plug);
+
+ // Check that plugin name is correct
+ LilvNode* name = lilv_plugin_get_name(plug);
+ TEST_ASSERT(!strcmp(lilv_node_as_string(name), "First name"));
+ lilv_node_free(name);
+
+ // Unload bundle from world and delete it
+ lilv_world_unload_bundle(world, bundle_uri);
+ delete_bundle();
+
+ // Create a new version of the same bundle, but with a different name
+ create_bundle(MANIFEST_PREFIXES
+ ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
+ BUNDLE_PREFIXES
+ ":plug a lv2:Plugin ; "
+ PLUGIN_NAME("Second name") " .");
+
+ // Load new bundle
+ lilv_world_load_bundle(world, bundle_uri);
+
+ // TODO: Mechanism to actually remove plugin from world list
+
+ // Check that plugin is present again
+ const LilvPlugin* plug2 = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
+ TEST_ASSERT(plug2);
+
+ // Check that plugin now has new name
+ LilvNode* name2 = lilv_plugin_get_name(plug2);
+ TEST_ASSERT(name2);
+ TEST_ASSERT(!strcmp(lilv_node_as_string(name2), "Second name"));
+ lilv_node_free(name2);
+
+ lilv_node_free(bundle_uri);
+ lilv_world_free(world);
+ world = NULL;
+
+ return 1;
+}
+
+/*****************************************************************************/
+
/* add tests here */
static struct TestCase tests[] = {
TEST_CASE(util),
@@ -1963,6 +2029,7 @@ static struct TestCase tests[] = {
TEST_CASE(string),
TEST_CASE(world),
TEST_CASE(state),
+ TEST_CASE(reload_bundle),
{ NULL, NULL }
};