diff options
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | lilv/lilv.h | 6 | ||||
-rw-r--r-- | src/lilv_internal.h | 5 | ||||
-rw-r--r-- | src/world.c | 103 | ||||
-rw-r--r-- | test/lilv_test.c | 71 |
5 files changed, 142 insertions, 47 deletions
@@ -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 } }; |