From 0bd3105f50f3c82586e0924a4be9977425caaf90 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Thu, 24 Nov 2011 00:53:45 +0000 Subject: [PATCH] Save references to external files in LV2 state as symbolic links. With this commit it is possible to archive sessions that contain plugins with complex file-containing state (e.g. Linuxsampler with a sample bank loaded) with any archive tool, e.g.: tar -hjcf session.tar.bz2 session Which will give you a fully self-contained archive of everything used in the session, so you can e.g. send it to a collaborator who may not have the same sample banks in the same place as you and it will work. git-svn-id: svn://localhost/ardour2/branches/3.0@10817 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/lv2_plugin.h | 2 ++ libs/ardour/lv2_plugin.cc | 54 +++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/libs/ardour/ardour/lv2_plugin.h b/libs/ardour/ardour/lv2_plugin.h index adbb26b832..6396e30038 100644 --- a/libs/ardour/ardour/lv2_plugin.h +++ b/libs/ardour/ardour/lv2_plugin.h @@ -150,6 +150,8 @@ class LV2Plugin : public ARDOUR::Plugin static uint32_t _midi_event_type; static uint32_t _state_path_type; + const std::string state_dir () const; + static int lv2_state_store_callback (void* handle, uint32_t key, diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc index 466579a8bc..cc03f9b193 100644 --- a/libs/ardour/lv2_plugin.cc +++ b/libs/ardour/lv2_plugin.cc @@ -26,6 +26,7 @@ #include #include +#include #include @@ -454,6 +455,13 @@ LV2Plugin::c_ui_type () return (void*)_impl->ui_type; } +const std::string +LV2Plugin::state_dir() const +{ + return Glib::build_filename(_session.plugins_dir(), + _insert_id.to_s()); +} + int LV2Plugin::lv2_state_store_callback(LV2_State_Handle handle, uint32_t key, @@ -527,13 +535,17 @@ LV2Plugin::lv2_state_abstract_path(LV2_State_Map_Path_Handle handle, return g_strdup(absolute_path); } - const std::string state_dir = Glib::build_filename(me->_session.plugins_dir(), - me->_insert_id.to_s()); + const std::string state_dir = me->state_dir(); char* ret = NULL; if (strncmp(absolute_path, state_dir.c_str(), state_dir.length())) { - ret = g_strdup(absolute_path); + // Path outside state directory, make symbolic link + const std::string name = Glib::path_get_basename(absolute_path); + const std::string path = Glib::build_filename(state_dir, name); + Gio::File::create_for_path(path)->make_symbolic_link(absolute_path); + ret = g_strndup(path.c_str(), path.length()); } else { + // Path inside the state directory, return relative path const std::string path(absolute_path + state_dir.length() + 1); ret = g_strndup(path.c_str(), path.length()); } @@ -558,10 +570,7 @@ LV2Plugin::lv2_state_absolute_path(LV2_State_Map_Path_Handle handle, ret = g_strdup(abstract_path); } else { const std::string apath(abstract_path); - const std::string state_dir = Glib::build_filename(me->_session.plugins_dir(), - me->_insert_id.to_s()); - const std::string path = Glib::build_filename(state_dir, - apath); + const std::string path = Glib::build_filename(me->state_dir(), apath); ret = g_strndup(path.c_str(), path.length()); } @@ -580,13 +589,9 @@ LV2Plugin::lv2_state_make_path(LV2_State_Make_Path_Handle handle, return g_strdup(path); } - const std::string abs_path = Glib::build_filename( - Glib::build_filename( - me->_session.plugins_dir(), - me->_insert_id.to_s()), - path); + const std::string abs_path = Glib::build_filename(me->state_dir(), path); + const std::string dirname = Glib::path_get_dirname(abs_path); - const std::string dirname = Glib::path_get_dirname(abs_path); g_mkdir_with_parents(dirname.c_str(), 0744); DEBUG_TRACE(DEBUG::LV2, string_compose("new file path %1 => %2\n", @@ -595,6 +600,26 @@ LV2Plugin::lv2_state_make_path(LV2_State_Make_Path_Handle handle, return g_strndup(abs_path.c_str(), abs_path.length()); } +static void +remove_directory(const std::string& path) +{ + if (!Glib::file_test(path, Glib::FILE_TEST_IS_DIR)) { + return; + } + + Glib::RefPtr dir = Gio::File::create_for_path(path); + Glib::RefPtr e = dir->enumerate_children(); + Glib::RefPtr fi; + while ((fi = e->next_file())) { + if (fi->get_type() == Gio::FILE_TYPE_DIRECTORY) { + remove_directory(fi->get_name()); + } else { + dir->get_child(fi->get_name())->remove(); + } + } + dir->remove(); +} + void LV2Plugin::add_state(XMLNode* root) const { @@ -633,6 +658,9 @@ LV2Plugin::add_state(XMLNode* root) const return; } + // Remove old state directory (FIXME: should this be preserved?) + remove_directory(state_dir()); + // Save plugin state to state object LV2State state(*this, _uri_map); state_iface->save(_impl->instance->lv2_handle,