Foundation for plugin-manager, persistent logs
This commit is contained in:
parent
c38be89bab
commit
fce374fd41
|
@ -3,7 +3,7 @@
|
|||
* Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
|
||||
* Copyright (C) 2008-2011 David Robillard <d@drobilla.net>
|
||||
* Copyright (C) 2009-2011 Carl Hetherington <carl@carlh.net>
|
||||
* Copyright (C) 2014-2019 Robin Gareus <robin@gareus.org>
|
||||
* Copyright (C) 2014-2021 Robin Gareus <robin@gareus.org>
|
||||
* Copyright (C) 2018 Ben Loftis <ben@harrisonconsoles.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -33,10 +33,12 @@
|
|||
#include <string>
|
||||
#include <set>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/container/set.hpp>
|
||||
|
||||
#include "ardour/libardour_visibility.h"
|
||||
#include "ardour/types.h"
|
||||
#include "ardour/plugin.h"
|
||||
#include "ardour/plugin_scan_result.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
|
@ -79,6 +81,9 @@ public:
|
|||
static uint32_t cache_version ();
|
||||
bool cache_valid () const;
|
||||
|
||||
void scan_log (std::vector<boost::shared_ptr<PluginScanLogEntry> >&) const;
|
||||
void clear_stale_log ();
|
||||
|
||||
/* always return LXVST for any VST subtype */
|
||||
static PluginType to_generic_vst (const PluginType);
|
||||
|
||||
|
@ -145,6 +150,26 @@ public:
|
|||
PBD::Signal3<void, ARDOUR::PluginType, std::string, std::string> PluginTagChanged; //PluginType t, string id, string tag
|
||||
|
||||
private:
|
||||
typedef boost::shared_ptr<PluginScanLogEntry> PSLEPtr;
|
||||
|
||||
struct PSLEPtrSort {
|
||||
bool operator() (PSLEPtr const& a, PSLEPtr const& b) const {
|
||||
return *a < *b;
|
||||
}
|
||||
};
|
||||
|
||||
typedef boost::container::set<PSLEPtr, PSLEPtrSort> PluginScanLog;
|
||||
PluginScanLog _plugin_scan_log;
|
||||
|
||||
PSLEPtr scan_log_entry (PluginType const type, std::string const& path) {
|
||||
PSLEPtr psl = PSLEPtr (new PluginScanLogEntry (type, path));
|
||||
PluginScanLog::iterator i = _plugin_scan_log.find (psl);
|
||||
if (i == _plugin_scan_log.end ()) {
|
||||
_plugin_scan_log.insert (psl);
|
||||
i = _plugin_scan_log.find (psl);
|
||||
}
|
||||
return *i;
|
||||
}
|
||||
|
||||
struct PluginTag {
|
||||
PluginType const type;
|
||||
|
@ -246,6 +271,9 @@ private:
|
|||
void load_tags ();
|
||||
void load_stats ();
|
||||
|
||||
void load_scanlog ();
|
||||
void save_scanlog ();
|
||||
|
||||
std::string sanitize_tag (const std::string) const;
|
||||
|
||||
void ladspa_refresh ();
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _ardour_plugin_scan_result_h_
|
||||
#define _ardour_plugin_scan_result_h_
|
||||
|
||||
#ifdef WAF_BUILD
|
||||
#include "libardour-config.h"
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ardour/plugin.h"
|
||||
#include "ardour/types.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class LIBARDOUR_API PluginScanLogEntry
|
||||
{
|
||||
public:
|
||||
PluginScanLogEntry (PluginType const, std::string const& path);
|
||||
PluginScanLogEntry (XMLNode const&);
|
||||
PluginScanLogEntry (PluginScanLogEntry const&);
|
||||
|
||||
enum PluginScanResult {
|
||||
OK = 0x000,
|
||||
New = 0x001, // plugin has no cache file, scan needed
|
||||
Updated = 0x002, // plugin is newer than cache, scan needed
|
||||
Error = 0x004, // scan failed
|
||||
Incompatible = 0x008, // plugin is not compatible (eg 32/64bit) or LV2 in VST2 path
|
||||
TimeOut = 0x010, // scan timed out
|
||||
Blacklisted = 0x100,
|
||||
Faulty = 0x017 // New | Updated | Error | Incompatible | TimeOut
|
||||
};
|
||||
|
||||
void reset ();
|
||||
void set_result (PluginScanResult);
|
||||
void msg (PluginScanResult, std::string msg = "");
|
||||
void add (PluginInfoPtr);
|
||||
|
||||
PluginInfoList const& nfo () const
|
||||
{
|
||||
return _info;
|
||||
}
|
||||
|
||||
XMLNode& state () const;
|
||||
|
||||
PluginType type () const
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
std::string path () const
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
|
||||
std::string log () const
|
||||
{
|
||||
return _scan_log;
|
||||
}
|
||||
|
||||
PluginScanResult result () const
|
||||
{
|
||||
return _result;
|
||||
}
|
||||
|
||||
bool recent () const
|
||||
{
|
||||
return _recent;
|
||||
}
|
||||
|
||||
bool operator== (PluginScanLogEntry const& other) const
|
||||
{
|
||||
return other._type == _type && other._path == _path;
|
||||
}
|
||||
|
||||
bool operator!= (PluginScanLogEntry const& other) const
|
||||
{
|
||||
return other._type != _type || other._path != _path;
|
||||
}
|
||||
|
||||
bool operator< (PluginScanLogEntry const& other) const
|
||||
{
|
||||
if (other._type == _type) {
|
||||
return _path < other._path;
|
||||
}
|
||||
return _type < other._type;
|
||||
}
|
||||
|
||||
private:
|
||||
PluginType _type;
|
||||
std::string _path;
|
||||
PluginScanResult _result;
|
||||
std::string _scan_log;
|
||||
PluginInfoList _info;
|
||||
bool _recent; // true: touched in this instance, false: loaded from disk
|
||||
};
|
||||
|
||||
} /* namespace ARDOUR */
|
||||
|
||||
#endif /* _ardour_plugin_scan_result_h_ */
|
|
@ -438,6 +438,8 @@ PluginManager::refresh (bool cache_only)
|
|||
return;
|
||||
}
|
||||
|
||||
load_scanlog ();
|
||||
|
||||
DEBUG_TRACE (DEBUG::PluginManager, "PluginManager::refresh\n");
|
||||
_cancel_scan = false;
|
||||
|
||||
|
@ -605,6 +607,8 @@ PluginManager::refresh (bool cache_only)
|
|||
all_plugs.insert(all_plugs.end(), _lua_plugin_info->begin(), _lua_plugin_info->end());
|
||||
}
|
||||
detect_type_ambiguities (all_plugs);
|
||||
|
||||
save_scanlog ();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2498,3 +2502,69 @@ PluginManager::lua_plugin_info ()
|
|||
assert(_lua_plugin_info);
|
||||
return *_lua_plugin_info;
|
||||
}
|
||||
|
||||
/* ****************************************************************************/
|
||||
|
||||
void
|
||||
PluginManager::scan_log (std::vector<boost::shared_ptr<PluginScanLogEntry> >& l) const
|
||||
{
|
||||
for (PluginScanLog::const_iterator i = _plugin_scan_log.begin(); i != _plugin_scan_log.end(); ++i) {
|
||||
l.push_back (*i);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginManager::clear_stale_log ()
|
||||
{
|
||||
for (PluginScanLog::const_iterator i = _plugin_scan_log.begin(); i != _plugin_scan_log.end();) {
|
||||
if (!(*i)->recent()) {
|
||||
i = _plugin_scan_log.erase (i);
|
||||
// TODO also remove cache file (and blacklist entry)
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginManager::load_scanlog ()
|
||||
{
|
||||
_plugin_scan_log.clear ();
|
||||
std::string path = Glib::build_filename (user_plugin_metadata_dir(), "scan_log");
|
||||
if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
XMLTree tree;
|
||||
if (!tree.read (path)) {
|
||||
error << string_compose (_("Cannot load Plugin Scan Log from '%1'."), path) << endmsg;
|
||||
return;
|
||||
}
|
||||
|
||||
for (XMLNodeConstIterator i = tree.root()->children().begin(); i != tree.root()->children().end(); ++i) {
|
||||
try {
|
||||
_plugin_scan_log.insert (PSLEPtr (new PluginScanLogEntry (**i)));
|
||||
} catch (...) {
|
||||
error << string_compose (_("Plugin Scan Log '%1' contains invalid information."), path) << endmsg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginManager::save_scanlog ()
|
||||
{
|
||||
std::string path = Glib::build_filename (user_plugin_metadata_dir(), "scan_log");
|
||||
XMLNode* root = new XMLNode (X_("PluginScanLog"));
|
||||
root->set_property ("version", 1);
|
||||
|
||||
for (PluginScanLog::const_iterator i = _plugin_scan_log.begin(); i != _plugin_scan_log.end(); ++i) {
|
||||
XMLNode& node = (*i)->state ();
|
||||
root->add_child_nocopy (node);
|
||||
}
|
||||
|
||||
XMLTree tree;
|
||||
tree.set_root (root);
|
||||
if (!tree.write (path)) {
|
||||
error << string_compose (_("Could not save Plugin Scan Log to %1"), path) << endmsg;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "pbd/convert.h"
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/failed_constructor.h"
|
||||
|
||||
#include "ardour/plugin_scan_result.h"
|
||||
#include "ardour/types_convert.h"
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
|
||||
inline PluginScanLogEntry::PluginScanResult operator|= (PluginScanLogEntry::PluginScanResult& a, const PluginScanLogEntry::PluginScanResult& b) {
|
||||
return a = static_cast<PluginScanLogEntry::PluginScanResult> (static_cast <int>(a) | static_cast<int> (b));
|
||||
}
|
||||
|
||||
inline PluginScanLogEntry::PluginScanResult operator&= (PluginScanLogEntry::PluginScanResult& a, const PluginScanLogEntry::PluginScanResult& b) {
|
||||
return a = static_cast<PluginScanLogEntry::PluginScanResult> (static_cast <int>(a) & static_cast<int> (b));
|
||||
}
|
||||
|
||||
PluginScanLogEntry::PluginScanLogEntry (PluginType const t, std::string const& p)
|
||||
: _type (t)
|
||||
, _path (p)
|
||||
{
|
||||
reset ();
|
||||
}
|
||||
|
||||
PluginScanLogEntry::PluginScanLogEntry (PluginScanLogEntry const& o)
|
||||
: _type (o._type)
|
||||
, _path (o._path)
|
||||
, _result (o._result)
|
||||
, _scan_log (o._scan_log)
|
||||
, _info (o._info)
|
||||
, _recent (o._recent)
|
||||
{
|
||||
}
|
||||
|
||||
PluginScanLogEntry::PluginScanLogEntry (XMLNode const& node)
|
||||
{
|
||||
reset ();
|
||||
|
||||
bool err = false;
|
||||
if (node.name () != "PluginScanLogEntry") {
|
||||
throw failed_constructor ();
|
||||
}
|
||||
int res = Error;
|
||||
_recent = false;
|
||||
|
||||
err |= !node.get_property ("type", _type);
|
||||
err |= !node.get_property ("path", _path);
|
||||
err |= !node.get_property ("scan-log", _scan_log);
|
||||
err |= !node.get_property ("scan-result", res);
|
||||
|
||||
_result = PluginScanResult (res);
|
||||
|
||||
if (err) {
|
||||
throw failed_constructor ();
|
||||
}
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
PluginScanLogEntry::state () const
|
||||
{
|
||||
XMLNode* node = new XMLNode ("PluginScanLogEntry");
|
||||
node->set_property ("type", _type);
|
||||
node->set_property ("path", _path);
|
||||
node->set_property ("scan-log", _scan_log);
|
||||
node->set_property ("scan-result", (int)_result);
|
||||
return *node;
|
||||
}
|
||||
|
||||
void
|
||||
PluginScanLogEntry::reset ()
|
||||
{
|
||||
_result = OK;
|
||||
_scan_log = "";
|
||||
_info.clear ();
|
||||
_recent = true;
|
||||
}
|
||||
|
||||
void
|
||||
PluginScanLogEntry::set_result (PluginScanResult r)
|
||||
{
|
||||
_result = r;
|
||||
_recent = true;
|
||||
}
|
||||
|
||||
void
|
||||
PluginScanLogEntry::add (PluginInfoPtr info)
|
||||
{
|
||||
_recent = true;
|
||||
_info.push_back (info);
|
||||
}
|
||||
|
||||
static bool invalid_char (unsigned char c)
|
||||
{
|
||||
return !isprint (c);
|
||||
}
|
||||
|
||||
void
|
||||
PluginScanLogEntry::msg (PluginScanResult r, std::string msg)
|
||||
{
|
||||
_result |= r;
|
||||
_recent = true;
|
||||
|
||||
/* some plugins include control chars (e.g. change terminal color) or
|
||||
* just print garbage. libXML saves this just fine but cannot read it:
|
||||
* "parser error: PCDATA invalid Char value"
|
||||
*/
|
||||
msg.erase (std::remove_if (msg.begin(), msg.end(), invalid_char), msg.end());
|
||||
|
||||
if (msg.empty ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (r) {
|
||||
case Error:
|
||||
PBD::warning << string_compose ("%1<%2>: %3", enum_2_string (_type), _path, msg) << endmsg;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_scan_log += msg;
|
||||
if (msg.at (msg.size() -1) != '\n') {
|
||||
_scan_log += "\n";
|
||||
}
|
||||
}
|
|
@ -176,6 +176,7 @@ libardour_sources = [
|
|||
'plugin.cc',
|
||||
'plugin_insert.cc',
|
||||
'plugin_manager.cc',
|
||||
'plugin_scan_result.cc',
|
||||
'polarity_processor.cc',
|
||||
'port.cc',
|
||||
'port_engine_shared.cc',
|
||||
|
|
Loading…
Reference in New Issue