25#include <magic_enum.hpp>
29#include <unordered_set>
40using namespace std::chrono_literals;
57 static std::mutex& registryLock = *
new std::mutex;
58 static std::map<wxString, std::unique_ptr<std::recursive_mutex>>& registry =
59 *
new std::map<wxString, std::unique_ptr<std::recursive_mutex>>;
61 std::lock_guard guard( registryLock );
62 std::unique_ptr<std::recursive_mutex>& slot = registry[aNickname];
65 slot = std::make_unique<std::recursive_mutex>();
79 std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_MANAGER_ADAPTER>> adapters;
95 std::vector<LIBRARY_TABLE_TYPE> aTablesToLoad )
114 wxCHECK_MSG(
false,
m_tables,
"Invalid scope passed to loadTables" );
118 std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>>& aTarget = getTarget();
120 if( aTablesToLoad.size() == 0 )
125 aTarget.erase( type );
129 if( fn.IsFileReadable() )
131 std::unique_ptr<LIBRARY_TABLE>
table = std::make_unique<LIBRARY_TABLE>( fn, aScope );
133 if(
table->Type() != type )
135 auto actualName = magic_enum::enum_name(
table->Type() );
136 auto expectedName = magic_enum::enum_name( type );
137 wxLogWarning( wxS(
"Library table '%s' has type %s but expected %s; skipping" ),
139 wxString( actualName.data(), actualName.size() ),
140 wxString( expectedName.data(), expectedName.size() ) );
144 aTarget[type] = std::move(
table );
149 wxLogTrace(
traceLibraries,
"No library table found at %s", fn.GetFullPath() );
157 std::unordered_set<wxString> seenTables;
162 seenTables.insert( aTable.Path() );
174 file.MakeAbsolute( wxFileName( aTable.Path() ).GetPath() );
177 wxString src = file.GetFullPath();
179 if( seenTables.contains( src ) )
181 wxLogTrace(
traceLibraries,
"Library table %s has already been loaded!", src );
183 row.SetErrorDescription(
_(
"A reference to this library table already exists" ) );
187 auto child = std::make_unique<LIBRARY_TABLE>( file, aRootTable.
Scope() );
189 processOneTable( *child );
194 row.SetErrorDescription( child->ErrorDescription() );
199 m_childTables.insert_or_assign( row.URI(), std::move( child ) );
204 processOneTable( aRootTable );
219 wxString tablePath = aTable.
Path();
226 const std::map<wxString, LIB_OVERRIDE>& overrides = it->second;
230 auto overIt = overrides.find( row.Nickname() );
232 if( overIt != overrides.end() )
234 row.SetDisabled( overIt->second.disabled );
235 row.SetHidden( overIt->second.hidden );
248 bool aDisabled,
bool aHidden )
253 wxCHECK( settings, );
255 if( !aDisabled && !aHidden )
261 settings->
m_LibOverrides[aTablePath][aNickname] = { aDisabled, aHidden };
270 wxCHECK( settings, );
277 tableIt->second.erase( aNickname );
279 if( tableIt->second.empty() )
291 default: wxCHECK(
false, wxEmptyString );
300 wxCHECK( !
m_tables.contains( aType ), );
322 const wxString& aPrefix ) :
328 wxFileName f( aBasePath,
"" );
334 .value_or(
nullptr );
338 wxDirTraverseResult
OnFile(
const wxString& aFilePath )
override
340 wxFileName file = wxFileName::FileName( aFilePath );
344 if( file.GetExt() == wxT(
"kicad_sym" )
351 return wxDIR_CONTINUE;
355 wxDirTraverseResult
OnDir(
const wxString& dirPath )
override
358 wxFileName dir = wxFileName::DirName( dirPath );
362 if( dirPath.EndsWith( wxS(
".pretty" ) )
368 else if( dirPath.EndsWith( designBlockExt )
375 return wxDIR_CONTINUE;
383 if( aTable->
HasRow( aNickname ) )
389 aNickname = wxString::Format(
"%s%s_%d",
m_lib_prefix, aBaseName, increment );
391 }
while( aTable->
HasRow( aNickname ) );
402 int aExtensionLength )
408 wxString versionedPath = wxString::Format( wxS(
"${%s}" ),
411 wxArrayString parts = aSource.GetDirs();
413 parts.Insert( versionedPath, 0 );
416 parts.Add( aSource.GetFullName() );
418 wxString libPath = wxJoin( parts,
'/' );
422 wxString
name = parts.Last().substr( 0, parts.Last().length() - aExtensionLength );
427 wxLogTrace(
traceLibraries,
"Manager: Adding PCM lib '%s' as '%s'", libPath, nickname );
439 wxLogTrace(
traceLibraries,
"Manager: Not adding existing PCM lib '%s'", libPath );
464 return fn.GetFullPath();
475 return fn.GetFullPath();
483 return wxString::Format( wxS(
"${%s}/%s" ), templateDirVar,
tableFileName( aType ) );
497 auto it = common->m_Env.vars.find( templateDirVar );
499 if( it != common->m_Env.vars.end() && it->second.GetDefinedExternally() )
509 if( wxFileName fn( aPath ); fn.IsFileReadable() )
529 std::vector<LIBRARY_TABLE_TYPE> invalidTables;
539 invalidTables.emplace_back( tableType );
542 return invalidTables;
551 table.SetType( aType );
552 table.Rows().clear();
556 if( aPopulateDefaultLibraries && defaultLib.IsFileReadable() )
564 else if( aPopulateDefaultLibraries )
566 auto typeName = magic_enum::enum_name( aType );
567 wxLogTrace(
traceLibraries,
"No stock library table for %s at '%s'; creating empty global table",
568 wxString( typeName.data(), typeName.size() ), defaultLib.GetFullPath() );
574 table.Format( &formatter );
593 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
594 adapter->GlobalTablesChanged( aTablesToLoad );
606 wxCHECK( settings, );
614 wxFileName d( *packagesPath,
"" );
619 wxDir dir( d.GetPath() );
621 dir.Traverse( traverser );
625 table->Save().map_error(
628 wxLogTrace(
traceLibraries, wxT(
"Warning: save failed after PCM auto-add: %s" ),
635 auto cleanupRemovedPCMLibraries =
643 auto toErase = std::ranges::remove_if(
table->Rows(),
646 if( !IsPcmManagedRow( aRow ) )
649 wxString path = GetFullURI( &aRow, true );
650 return !wxFileName::Exists( path );
653 bool hadRemovals = !toErase.empty();
654 table->Rows().erase( toErase.begin(), toErase.end() );
658 table->Save().map_error(
661 wxLogTrace(
traceLibraries, wxT(
"Warning: save failed after PCM auto-remove: %s" ),
693 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
694 adapter->ProjectChanged();
702 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
703 adapter->AbortAsyncLoad();
708 std::unique_ptr<LIBRARY_MANAGER_ADAPTER>&& aAdapter )
712 wxCHECK_MSG( !
m_adapters.contains( aType ), ,
"You should only register an adapter once!" );
720 std::unique_ptr<LIBRARY_MANAGER_ADAPTER> retired;
753 wxCHECK_MSG(
false, std::nullopt,
"Table() requires a single scope" );
760 magic_enum::enum_name( aType ) );
771 if( !
Project().IsNullProject() )
786 bool aIncludeInvalid )
const
788 std::map<wxString, LIBRARY_TABLE_ROW*> rows;
789 std::vector<wxString> rowOrder;
791 std::list<std::ranges::ref_view<const std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>>>> tables;
796 tables = { std::views::all(
m_tables ) };
811 std::function<void(
const std::unique_ptr<LIBRARY_TABLE>&,
bool parentHidden)> processTable =
812 [&](
const std::unique_ptr<LIBRARY_TABLE>& aTable,
const bool parentHidden )
814 if( aTable->Type() != aType )
817 if( aTable->IsOk() || aIncludeInvalid )
821 if( row.IsOk() || aIncludeInvalid )
825 row.SetHidden(
true );
840 if( !rows.contains( row.Nickname() ) )
841 rowOrder.emplace_back( row.Nickname() );
843 rows[ row.Nickname() ] = &row;
850 for(
const std::unique_ptr<LIBRARY_TABLE>&
table :
851 std::views::join( tables ) | std::views::values )
853 processTable(
table,
false );
856 std::vector<LIBRARY_TABLE_ROW*> ret;
858 for(
const wxString& row : rowOrder )
859 ret.emplace_back( rows[row] );
870 auto key = std::make_tuple( aType, aScope, aNickname );
878 if( row->Nickname() == aNickname )
881 m_rowCache[std::make_tuple( aType, aScope, aNickname )] = row;
891 const wxString& aUri,
907 if( std::optional<LIBRARY_MANAGER_ADAPTER*> adapter =
Adapter( aType ); adapter )
908 ( *adapter )->ReloadLibraryEntry( aNickname, aScope );
913 const wxString& aNickname )
915 if( std::optional<LIBRARY_MANAGER_ADAPTER*> adapter =
Adapter( aType ); adapter )
916 return ( *adapter )->LoadLibraryEntry( aNickname );
923 std::initializer_list<LIBRARY_TABLE_TYPE> aTablesToLoad )
932 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
933 adapter->ProjectTablesChanged( aTablesToLoad );
936 if( wxFileName::IsDirReadable( aProjectPath ) )
950 if( aTablesToLoad.size() == 0 )
960 wxLogTrace(
traceLibraries,
"New project path %s is not readable, not loading project tables", aProjectPath );
970 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
971 adapter->ProjectTablesReloaded( aTablesToLoad );
977 std::initializer_list<LIBRARY_TABLE_TYPE> aTablesToLoad )
994 if( std::optional<const LIBRARY_TABLE_ROW*>
result =
GetRow( aType, aNickname ) )
1016 path.MakeAbsolute();
1017 return path.GetFullPath();
1032 const wxString& uri = aRow.
URI();
1034 if( !uri.StartsWith( wxS(
"${" ) ) )
1037 size_t end = uri.find( wxS(
'}' ) );
1039 if(
end == wxString::npos ||
end <= 2 )
1042 wxString varName = uri.SubString( 2,
end - 1 );
1050 if(
end + 1 >= uri.length() || uri[
end + 1] != wxS(
'/' ) )
1057 wxArrayString parts = wxSplit( uri.Mid(
end + 2 ),
'/',
'\0' );
1059 if( parts.size() < 3 )
1062 for(
const wxString& part : parts )
1064 if( part.IsEmpty() )
1068 wxString category = parts[0];
1069 wxString leaf = parts.Last();
1074 auto hasLibExtension = [&leaf](
const wxString& aExt )
1076 return leaf.length() > aExt.length() && leaf.EndsWith( aExt );
1079 if( category == wxS(
"symbols" ) )
1080 return hasLibExtension( wxS(
".kicad_sym" ) );
1082 if( category == wxS(
"footprints" ) )
1083 return hasLibExtension( wxS(
".pretty" ) );
1085 if( category == wxS(
"design_blocks" ) )
1087 static const wxString designBlockExt =
1090 return hasLibExtension( designBlockExt );
1100 if( aURI1.Find(
"://" ) != wxNOT_FOUND )
1103 return aURI1 == aURI2;
1107 const wxFileName fn1( aURI1 );
1108 const wxFileName fn2( aURI2 );
1153 std::vector<std::unique_ptr<IO_BASE>> retired;
1164 retired.push_back( std::move( entry.second.plugin ) );
1178 bool me = aChangedTables.size() == 0;
1182 if( type ==
Type() )
1195 std::map<wxString, LIB_DATA> retired;
1209 std::vector<std::map<wxString, LIB_DATA>::node_type> retired;
1216 if( it->second.global_owner ==
this )
1217 retired.push_back(
globalLibs().extract( it++ ) );
1226 bool me = aChangedTables.size() == 0;
1230 if( type ==
Type() )
1245 std::initializer_list<LIBRARY_TABLE_TYPE> aChangedTables )
1247 bool me = aChangedTables.size() == 0;
1251 if( type ==
Type() )
1268 std::vector<std::map<wxString, LIB_DATA>::node_type> retired;
1298 if( loadedRow->
URI() == aRow.
URI() && loadedRow->
Type() == aRow.
Type() )
1315 std::optional<LIB_STATUS> status =
CheckLibrary( &lib );
1317 if( status.has_value() )
1321 if( status.value().error.has_value() )
1332 aRow.
SetOk(
false );
1357 return row->Nickname();
1360 return std::nullopt;
1366 std::vector<wxString> ret;
1367 std::vector<LIBRARY_TABLE_ROW*> rows =
m_manager.Rows(
Type() );
1369 wxLogTrace(
traceLibraries,
"GetLibraryNames: checking %zu rows from table", rows.size() );
1373 wxString nickname = row->Nickname();
1374 std::optional<const LIB_DATA*> loaded =
fetchIfLoaded( nickname );
1377 ret.emplace_back( nickname );
1382 wxLogTrace(
traceLibraries,
"GetLibraryNames: returning %zu of %zu libraries", ret.size(), rows.size() );
1389 std::optional<const LIB_DATA*> r =
fetchIfLoaded( aNickname );
1392 return !aCheckEnabled || !r.value()->row->Disabled();
1407 std::lock_guard pluginGuard(
pluginMutex( aNickname ) );
1425 if( std::optional<const LIB_DATA*> optRow =
fetchIfLoaded( aNickname ); optRow )
1426 return ( *optRow )->row->Description();
1428 return std::nullopt;
1433 bool aIncludeInvalid )
const
1447 const wxString& aUri,
1484 return std::nullopt;
1487 return loaded /
static_cast<float>( total );
1493 wxLogTrace(
traceLibraries,
"BlockUntilLoaded: entry, acquiring m_loadMutex" );
1494 std::unique_lock<std::mutex> asyncLock(
m_loadMutex );
1498 for(
const std::future<void>& future :
m_futures )
1501 wxLogTrace(
traceLibraries,
"BlockUntilLoaded: all futures complete, loadCount=%zu, loadTotal=%zu",
1532 return it->second.status.error;
1539 return it->second.status.error;
1542 return std::nullopt;
1548 std::vector<std::pair<wxString, LIB_STATUS>> ret;
1552 if( row->Disabled() )
1557 ret.emplace_back( std::make_pair( row->Nickname(), *
result ) );
1567 ret.emplace_back( std::make_pair( row->Nickname(),
1578 std::vector<KI_ERROR> errors;
1584 wxString title = status.error->message.BeforeFirst(
'\n' );
1585 title.StartsWith( wxS(
"IO_ERROR: " ), &title );
1586 errors.emplace_back(
1588 .SetDescription( title )
1590 .SetDebugText( status.error->details )
1607 return std::nullopt;
1619 std::shared_mutex& aMutex )
1621 bool wasLoaded =
false;
1622 std::map<wxString, LIB_DATA>::node_type retired;
1625 std::unique_lock lock( aMutex );
1626 auto it = aTarget.find( aNickname );
1628 if( it != aTarget.end() && it->second.plugin )
1631 retired = aTarget.extract( it );
1646 else if( !
result.has_value() )
1648 wxLogTrace(
traceLibraries,
"ReloadLibraryEntry: failed to reload %s (%s): %s",
1649 aNickname, magic_enum::enum_name( aScopeToReload ),
1650 result.error().message );
1682 std::lock_guard pluginGuard(
pluginMutex( aNickname ) );
1699 std::lock_guard pluginGuard(
pluginMutex( aNickname ) );
1708 wxLogTrace(
traceLibraries,
"CreateLibrary: IO_ERROR for %s: %s",
1709 aNickname, ioe.
What() );
1712 catch(
const std::exception& e )
1714 wxLogTrace(
traceLibraries,
"CreateLibrary: std::exception for %s: %s",
1715 aNickname, e.what() );
1720 wxLogTrace(
traceLibraries,
"CreateLibrary: library row '%s' not found", aNickname );
1741 return std::nullopt;
1746 return std::nullopt;
1756 return std::nullopt;
1760 return std::nullopt;
1774 return std::nullopt;
1779 return std::nullopt;
1789 return std::nullopt;
1793 return std::nullopt;
1799 std::map<wxString, LIB_DATA>& aTarget,
1800 std::shared_mutex& aMutex )
1802 bool present =
false;
1805 std::shared_lock lock( aMutex );
1806 present = aTarget.contains( aNickname ) && aTarget.at( aNickname ).plugin;
1814 wxLogTrace(
traceLibraries,
"Library %s (%s) not yet loaded, will attempt...",
1815 aNickname, magic_enum::enum_name( aScope ) );
1820 std::unique_ptr<IO_BASE> candidate( *
plugin );
1821 std::unique_lock lock( aMutex );
1829 slot.
plugin = std::move( candidate );
1839 return tl::unexpected(
plugin.error() );
1846 std::shared_lock lock( aMutex );
1847 return &aTarget.at( aNickname );
1864 wxString msg = wxString::Format(
_(
"Library %s not found" ), aNickname );
1875 return it->second.status;
1882 return it->second.status;
1885 return std::nullopt;
1891 std::unique_lock<std::mutex> asyncLock(
m_loadMutex, std::try_to_lock );
1897 []( std::future<void>& aFuture )
1899 return aFuture.valid()
1900 && aFuture.wait_for( 0s ) == std::future_status::ready;
1905 wxLogTrace(
traceLibraries,
"Cannot AsyncLoad, futures from a previous call remain!" );
1909 std::vector<LIBRARY_TABLE_ROW*> rows =
m_manager.Rows(
Type() );
1916 wxLogTrace(
traceLibraries,
"AsyncLoad: no libraries left to load; exiting" );
1923 [&](
const wxString& aLib, std::map<wxString, LIB_DATA>& aMap, std::shared_mutex& aMutex )
1925 std::shared_lock lock( aMutex );
1927 if(
auto it = aMap.find( aLib ); it != aMap.end() )
1929 LOAD_STATUS status = it->second.status.load_status;
1947 auto workQueue = std::make_shared<std::vector<LOAD_WORK>>();
1948 workQueue->reserve( rows.size() );
1952 wxString nickname = row->Nickname();
1957 if( row->Disabled() )
1975 workQueue->emplace_back( LOAD_WORK{ nickname, scope,
getUri( row ) } );
1978 if( workQueue->empty() )
1980 wxLogTrace(
traceLibraries,
"AsyncLoad: all libraries already loaded; exiting" );
1987 size_t poolSize =
tp.get_thread_count();
1988 size_t maxLoadThreads = std::max<size_t>( 1, poolSize > 2 ? poolSize - 2 : 1 );
1989 size_t numWorkers = std::min( maxLoadThreads, workQueue->size() );
1991 auto workIndex = std::make_shared<std::atomic<size_t>>( 0 );
1993 wxLogTrace(
traceLibraries,
"AsyncLoad: %zu libraries to load, using %zu worker threads (pool has %zu)",
1994 workQueue->size(), numWorkers, poolSize );
1996 for(
size_t w = 0; w < numWorkers; ++w )
1999 [
this, workQueue, workIndex]()
2003 if( m_abort.load() )
2006 size_t idx = workIndex->fetch_add( 1 );
2008 if( idx >= workQueue->size() )
2011 const LOAD_WORK& work = ( *workQueue )[idx];
2012 LIBRARY_RESULT<LIB_DATA*> result = loadIfNeeded( work.nickname );
2014 if( result.has_value() )
2016 LIB_DATA* lib = *result;
2021 std::unique_lock lock(
2022 work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
2024 : m_librariesMutex );
2025 lib->status.load_status = LOAD_STATUS::LOADING;
2028 enumerateLibrary( lib, work.uri );
2031 std::unique_lock lock(
2032 work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
2034 : m_librariesMutex );
2035 lib->status.load_status = LOAD_STATUS::LOADED;
2038 catch( IO_ERROR& e )
2040 std::unique_lock lock(
2041 work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
2043 : m_librariesMutex );
2044 lib->status.load_status = LOAD_STATUS::LOAD_ERROR;
2045 lib->status.error = LIBRARY_ERROR( e.Problem(), e.Where() );
2046 wxLogTrace( traceLibraries,
"%s: plugin threw exception: %s",
2047 work.nickname, e.What() );
2052 std::unique_lock lock(
2053 work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
2055 : m_librariesMutex );
2057 std::map<wxString, LIB_DATA>& target =
2058 ( work.scope == LIBRARY_TABLE_SCOPE::GLOBAL ) ? globalLibs()
2061 target[work.nickname].status = LIB_STATUS( {
2062 .load_status = LOAD_STATUS::LOAD_ERROR,
2063 .error = result.error()
2073 wxLogTrace(
traceLibraries,
"Started async load of %zu libraries", workQueue->size() );
virtual bool DeleteLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr)
Delete an existing library and returns true, or if library does not exist returns false,...
virtual bool IsLibraryWritable(const wxString &aLibraryPath)
Return true if the library at aLibraryPath is writable.
virtual void CreateLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr)
Create a new empty library at aLibraryPath empty.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
std::map< wxString, std::map< wxString, LIB_OVERRIDE > > m_LibOverrides
Overrides for libraries in read-only nested tables.
Holds a structured error message.
The interface used by the classes that actually can load IO plugins for the different parts of KiCad ...
std::optional< float > AsyncLoadProgress() const
Returns the fraction of the libraries queued by AsyncLoad() that have been processed,...
virtual std::optional< LIB_STATUS > LoadOne(LIB_DATA *aLib)=0
std::vector< KI_ERROR > GetLibraryLoadErrors() const
Returns all library load errors as newline-separated strings for display.
void resetProjectCache()
Aborts pending loads and resets every project-scope cache entry in place (plugin and row cleared,...
virtual std::optional< LIBRARY_ERROR > LibraryError(const wxString &aNickname) const
void ReloadLibraryEntry(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH)
Synchronously recreates the plugin for and reloads the given library.
std::optional< LIB_STATUS > GetLibraryStatus(const wxString &aNickname) const
Returns the status of a loaded library, or nullopt if the library hasn't been loaded (yet)
virtual ~LIBRARY_MANAGER_ADAPTER()
std::optional< LIBRARY_TABLE * > ProjectTable() const
Retrieves the project library table for this adapter type, or nullopt if one doesn't exist.
void AbortAsyncLoad()
Aborts any async load in progress; blocks until fully done aborting.
void ProjectTablesChanged(std::initializer_list< LIBRARY_TABLE_TYPE > aChangedTables={})
Notify the adapter that the project library tables are about to be rebuilt.
LIBRARY_TABLE * GlobalTable() const
Retrieves the global library table for this adapter type.
virtual std::shared_mutex & globalLibsMutex()=0
void evictOwnedGlobalEntries()
Erases this adapter's own entries (LIB_DATA::global_owner == this) from the process-wide globalLibs()...
LIBRARY_MANAGER_ADAPTER(LIBRARY_MANAGER &aManager)
Constructs a type-specific adapter into the library manager.
void CheckTableRow(LIBRARY_TABLE_ROW &aRow)
bool IsLibraryLoaded(const wxString &aNickname)
std::vector< LIBRARY_TABLE_ROW * > Rows(LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH, bool aIncludeInvalid=false) const
Like LIBRARY_MANAGER::Rows but filtered to the LIBRARY_TABLE_TYPE of this adapter.
std::optional< LIBRARY_TABLE_ROW * > FindRowByURI(const wxString &aUri, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::FindRowByURI but filtered to the LIBRARY_TABLE_TYPE of this adapter.
wxString getUri(const LIBRARY_TABLE_ROW *aRow) const
virtual std::map< wxString, LIB_DATA > & globalLibs()=0
virtual LIBRARY_TABLE_TYPE Type() const =0
The type of library table this adapter works with.
bool DeleteLibrary(const wxString &aNickname)
Deletes the given library from disk if it exists; returns true if deleted.
LIBRARY_RESULT< LIB_DATA * > loadIfNeeded(const wxString &aNickname)
Fetches a loaded library, triggering a load of that library if it isn't loaded yet.
std::optional< wxString > FindLibraryByURI(const wxString &aURI) const
std::shared_mutex m_librariesMutex
LIBRARY_MANAGER & Manager() const
void abortLoad()
Aborts any async load in progress; blocks until fully done aborting.
std::optional< wxString > GetLibraryDescription(const wxString &aNickname) const
virtual LIBRARY_RESULT< IO_BASE * > createPlugin(const LIBRARY_TABLE_ROW *row)=0
Creates a concrete plugin for the given row.
void GlobalTablesChanged(std::initializer_list< LIBRARY_TABLE_TYPE > aChangedTables={})
Notify the adapter that the global library tables have changed.
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library tables.
std::optional< LIBRARY_TABLE_ROW * > GetRow(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::GetRow but filtered to the LIBRARY_TABLE_TYPE of this adapter.
std::map< wxString, LIB_DATA > m_libraries
virtual IO_BASE * plugin(const LIB_DATA *aRow)=0
std::vector< wxString > GetLibraryNames() const
Returns a list of library nicknames that are available (skips any that failed to load)
virtual void ProjectChanged()
Notify the adapter that the active project has changed.
LIBRARY_RESULT< LIB_DATA * > loadFromScope(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope, std::map< wxString, LIB_DATA > &aTarget, std::shared_mutex &aMutex)
virtual std::optional< LIB_STATUS > CheckLibrary(LIB_DATA *aLib)
Validates that a library is loadable. May not necessarily load the library!
std::vector< std::future< void > > m_futures
static std::recursive_mutex & pluginMutex(const wxString &aNickname)
Serializes access to a library's shared plugin instance so its single mutable cache is not raced by c...
bool CreateLibrary(const wxString &aNickname)
Creates the library (i.e. saves to disk) for the given row if it exists.
void AsyncLoad()
Loads all available libraries for this adapter type in the background.
virtual bool IsWritable(const wxString &aNickname) const
Return true if the given nickname exists and is not a read-only library.
std::vector< std::pair< wxString, LIB_STATUS > > GetLibraryStatuses() const
Returns a list of all library nicknames and their status (even if they failed to load)
std::atomic< size_t > m_loadTotal
void ProjectTablesReloaded(std::initializer_list< LIBRARY_TABLE_TYPE > aChangedTables={})
Complements ProjectTablesChanged by erasing project-scope cache entries whose nicknames no longer app...
std::atomic< size_t > m_loadCount
LIBRARY_MANAGER & m_manager
std::optional< LIB_STATUS > LoadLibraryEntry(const wxString &aNickname)
Synchronously loads the named library to LOADED state.
std::optional< const LIB_DATA * > fetchIfLoaded(const wxString &aNickname) const
void ReloadTables(LIBRARY_TABLE_SCOPE aScope, std::initializer_list< LIBRARY_TABLE_TYPE > aTablesToLoad={})
static wxString StockTableTokenizedURI(LIBRARY_TABLE_TYPE aType)
static wxString ExpandURI(const wxString &aShortURI, const PROJECT &aProject)
const PROJECT *const m_project
std::mutex m_rowCacheMutex
void ClearLibOverride(const wxString &aTablePath, const wxString &aNickname)
Removes any override for a library that no longer needs one.
std::optional< LIBRARY_MANAGER_ADAPTER * > Adapter(LIBRARY_TABLE_TYPE aType) const
void applyLibOverrides(LIBRARY_TABLE &aTable)
Applies user overrides (disabled/hidden) to rows of a read-only nested table.
std::map< wxString, std::unique_ptr< LIBRARY_TABLE > > m_childTables
Map of full URI to table object for tables that are referenced by global or project tables.
void loadNestedTables(LIBRARY_TABLE &aTable)
std::map< ROW_CACHE_KEY, LIBRARY_TABLE_ROW * > m_rowCache
bool RemoveAdapter(LIBRARY_TABLE_TYPE aType, LIBRARY_MANAGER_ADAPTER *aAdapter)
const PROJECT & Project() const
void ReloadLibraryEntry(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH)
Synchronously recreates the plugin for and reloads the given library.
static bool UrisAreEquivalent(const wxString &aURI1, const wxString &aURI2)
std::mutex m_adaptersMutex
std::optional< LIBRARY_TABLE * > Table(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope)
Retrieves a given table; creating a new empty project table if a valid project is loaded and the give...
void ApplyLibOverrides(LIBRARY_TABLE &aTable)
Applies stored user overrides (disabled/hidden) to rows of a read-only table.
void RegisterAdapter(LIBRARY_TABLE_TYPE aType, std::unique_ptr< LIBRARY_MANAGER_ADAPTER > &&aAdapter)
static wxString DefaultGlobalTablePath(LIBRARY_TABLE_TYPE aType)
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false)
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
static std::vector< LIBRARY_TABLE_TYPE > InvalidGlobalTables()
void createEmptyTable(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope)
void AbortAsyncLoads()
Abort any async library loading operations in progress.
std::optional< LIB_STATUS > LoadLibraryEntry(LIBRARY_TABLE_TYPE aType, const wxString &aNickname)
Synchronously loads the named library to LOADED state for the given type.
static bool GlobalTablesValid()
std::map< LIBRARY_TABLE_TYPE, std::unique_ptr< LIBRARY_TABLE > > m_projectTables
std::optional< LIBRARY_TABLE_ROW * > FindRowByURI(LIBRARY_TABLE_TYPE aType, const wxString &aUri, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
void SetLibOverride(const wxString &aTablePath, const wxString &aNickname, bool aDisabled, bool aHidden)
Set a user override for a library in a read-only nested table.
bool IsProjectScoped() const
void LoadProjectTables(std::initializer_list< LIBRARY_TABLE_TYPE > aTablesToLoad={})
(Re)loads the project library tables in the given list, or all tables if no list is given
static bool CreateGlobalTable(LIBRARY_TABLE_TYPE aType, bool aPopulateDefaultLibraries)
void loadTables(const wxString &aTablePath, LIBRARY_TABLE_SCOPE aScope, std::vector< LIBRARY_TABLE_TYPE > aTablesToLoad={})
static wxString tableFileName(LIBRARY_TABLE_TYPE aType)
static bool IsPcmManagedRow(const LIBRARY_TABLE_ROW &aRow)
Return true if a library table row was added by the Plugin and Content Manager.
std::vector< LIBRARY_TABLE_ROW * > Rows(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH, bool aIncludeInvalid=false) const
Returns a flattened list of libraries of the given type.
void LoadGlobalTables(std::initializer_list< LIBRARY_TABLE_TYPE > aTablesToLoad={})
(Re)loads the global library tables in the given list, or all tables if no list is given
std::map< LIBRARY_TABLE_TYPE, std::unique_ptr< LIBRARY_TABLE > > m_tables
static wxString StockTableReferenceURI(LIBRARY_TABLE_TYPE aType)
static wxString StockTablePath(LIBRARY_TABLE_TYPE aType)
std::optional< LIBRARY_TABLE_ROW * > GetRow(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH)
void ProjectChanged()
Notify all adapters that the project has changed.
static bool IsTableValid(const wxString &aPath)
LIBRARY_MANAGER(const PROJECT *aProject=nullptr)
An explicit project is borrowed until this manager and its adapters are destroyed.
std::map< LIBRARY_TABLE_TYPE, std::unique_ptr< LIBRARY_MANAGER_ADAPTER > > m_adapters
void SetNickname(const wxString &aNickname)
void SetOk(bool aOk=true)
void SetType(const wxString &aType)
void SetErrorDescription(const wxString &aDescription)
std::map< std::string, UTF8 > GetOptionsMap() const
void SetDescription(const wxString &aDescription)
const wxString & Type() const
static const wxString TABLE_TYPE_NAME
void SetURI(const wxString &aUri)
const wxString & URI() const
const wxString & Nickname() const
bool IsReadOnly() const
Returns true if the underlying file exists but is not writable.
LIBRARY_TABLE_ROW & InsertRow()
Builds a new row and inserts it at the end of the table; returning a reference to the row.
const wxString & Path() const
LIBRARY_TABLE_SCOPE Scope() const
bool HasRow(const wxString &aNickname) const
bool HasRowWithURI(const wxString &aUri, const PROJECT &aProject, bool aSubstituted=false) const
Returns true if the given (fully-expanded) URI exists as a library in this table.
const std::deque< LIBRARY_TABLE_ROW > & Rows() const
static wxString GetStockTemplatesPath()
Gets the stock (install) templates path.
static wxString GetUserSettingsPath()
Return the user configuration path used to store KiCad's configuration files.
LIBRARY_TABLE * m_designBlockTable
std::set< LIBRARY_TABLE * > m_modified
LIBRARY_MANAGER & m_manager
std::set< LIBRARY_TABLE * > Modified() const
const PROJECT & m_project
PCM_LIB_TRAVERSER(const wxString &aBasePath, LIBRARY_MANAGER &aManager, const wxString &aPrefix)
void ensureUnique(LIBRARY_TABLE *aTable, const wxString &aBaseName, wxString &aNickname) const
LIBRARY_TABLE * m_symbolTable
wxDirTraverseResult OnDir(const wxString &dirPath) override
Handles footprint library and design block library directories, minimum nest level 3.
void addRowIfNecessary(LIBRARY_TABLE *aTable, const wxFileName &aSource, ADD_MODE aMode, int aExtensionLength)
LIBRARY_TABLE * m_fpTable
wxDirTraverseResult OnFile(const wxString &aFilePath) override
Handles symbol library files, minimum nest level 2.
size_t m_prefix_dir_count
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
virtual SETTINGS_MANAGER & GetSettingsManager() const
Container for project specific data.
T * GetAppSettings(const char *aFilename)
Return a handle to the a given settings by type.
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
static void ResolvePossibleSymlinks(wxFileName &aFilename)
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject, bool aAllowEscapes)
Replace any environment variable & text variable references with their values.
Functions related to environment variables, including help functions.
static const std::string KiCadDesignBlockLibPathExtension
static const std::string SymbolLibraryTableFileName
static const std::string DesignBlockLibraryTableFileName
static const std::string FootprintLibraryTableFileName
const wxChar *const traceLibraries
Flag to enable library table and library manager tracing.
std::map< wxString, ENV_VAR_ITEM > ENV_VAR_MAP
LOAD_STATUS
Status of a library load managed by a library adapter.
tl::expected< ResultType, LIBRARY_ERROR > LIBRARY_RESULT
KICOMMON_API bool IsVersionedEnvVar(const wxString &aName, const wxString &aBaseName)
Test whether a name is a versioned KiCad environment variable for the given base, i....
KICOMMON_API std::optional< wxString > GetVersionedEnvVarValue(const std::map< wxString, ENV_VAR_ITEM > &aMap, const wxString &aBaseName)
Attempt to retrieve the value of a versioned environment variable, such as KICAD8_TEMPLATE_DIR.
KICOMMON_API wxString GetVersionedEnvVarName(const wxString &aBaseName)
Construct a versioned environment variable based on this KiCad major version.
PGM_BASE & Pgm()
The global program "get" accessor.
void StrNumSort(T &aList, CASE_SENSITIVITY aCaseSensitivity)
Sort a container of wxString objects, in place, using the StrNumCmp() function.
std::vector< LIBRARY_TABLE > tables
Storage for an actual loaded library (including library content owned by the plugin)
std::unique_ptr< IO_BASE > plugin
Never destroyed while holding the map's mutex; a plugin's worker thread may be blocked on it.
const LIBRARY_MANAGER_ADAPTER * global_owner
const LIBRARY_TABLE_ROW * row
The overall status of a loaded or loading library.
wxString result
Test unit parsing edge cases and error handling.
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
wxLogTrace helper definitions.
Definition of file extensions used in Kicad.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().