Foundation for plugin-manager, persistent logs

This commit is contained in:
Robin Gareus 2021-05-24 00:01:12 +02:00
parent c38be89bab
commit fce374fd41
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
5 changed files with 363 additions and 1 deletions

View File

@ -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 ();

View File

@ -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_ */

View File

@ -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;
}
}

View File

@ -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";
}
}

View File

@ -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',