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>();
86 std::vector<LIBRARY_TABLE_TYPE> aTablesToLoad )
105 wxCHECK_MSG(
false,
m_tables,
"Invalid scope passed to loadTables" );
109 std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>>& aTarget = getTarget();
111 if( aTablesToLoad.size() == 0 )
116 aTarget.erase( type );
120 if( fn.IsFileReadable() )
122 std::unique_ptr<LIBRARY_TABLE>
table = std::make_unique<LIBRARY_TABLE>( fn, aScope );
124 if(
table->Type() != type )
126 auto actualName = magic_enum::enum_name(
table->Type() );
127 auto expectedName = magic_enum::enum_name( type );
128 wxLogWarning( wxS(
"Library table '%s' has type %s but expected %s; skipping" ),
130 wxString( actualName.data(), actualName.size() ),
131 wxString( expectedName.data(), expectedName.size() ) );
135 aTarget[type] = std::move(
table );
140 wxLogTrace(
traceLibraries,
"No library table found at %s", fn.GetFullPath() );
148 std::unordered_set<wxString> seenTables;
153 seenTables.insert( aTable.Path() );
165 file.MakeAbsolute( wxFileName( aTable.Path() ).GetPath() );
168 wxString src = file.GetFullPath();
170 if( seenTables.contains( src ) )
172 wxLogTrace(
traceLibraries,
"Library table %s has already been loaded!", src );
174 row.SetErrorDescription(
_(
"A reference to this library table already exists" ) );
178 auto child = std::make_unique<LIBRARY_TABLE>( file, aRootTable.
Scope() );
180 processOneTable( *child );
185 row.SetErrorDescription( child->ErrorDescription() );
190 m_childTables.insert_or_assign( row.URI(), std::move( child ) );
195 processOneTable( aRootTable );
210 wxString tablePath = aTable.
Path();
217 const std::map<wxString, LIB_OVERRIDE>& overrides = it->second;
221 auto overIt = overrides.find( row.Nickname() );
223 if( overIt != overrides.end() )
225 row.SetDisabled( overIt->second.disabled );
226 row.SetHidden( overIt->second.hidden );
239 bool aDisabled,
bool aHidden )
244 wxCHECK( settings, );
246 if( !aDisabled && !aHidden )
252 settings->
m_LibOverrides[aTablePath][aNickname] = { aDisabled, aHidden };
261 wxCHECK( settings, );
268 tableIt->second.erase( aNickname );
270 if( tableIt->second.empty() )
282 default: wxCHECK(
false, wxEmptyString );
291 wxCHECK( !
m_tables.contains( aType ), );
313 const wxString& aPrefix ) :
319 wxFileName f( aBasePath,
"" );
325 .value_or(
nullptr );
329 wxDirTraverseResult
OnFile(
const wxString& aFilePath )
override
331 wxFileName file = wxFileName::FileName( aFilePath );
335 if( file.GetExt() == wxT(
"kicad_sym" )
342 return wxDIR_CONTINUE;
346 wxDirTraverseResult
OnDir(
const wxString& dirPath )
override
349 wxFileName dir = wxFileName::DirName( dirPath );
353 if( dirPath.EndsWith( wxS(
".pretty" ) )
359 else if( dirPath.EndsWith( designBlockExt )
366 return wxDIR_CONTINUE;
374 if( aTable->
HasRow( aNickname ) )
380 aNickname = wxString::Format(
"%s%s_%d",
m_lib_prefix, aBaseName, increment );
382 }
while( aTable->
HasRow( aNickname ) );
393 int aExtensionLength )
399 wxString versionedPath = wxString::Format( wxS(
"${%s}" ),
402 wxArrayString parts = aSource.GetDirs();
404 parts.Insert( versionedPath, 0 );
407 parts.Add( aSource.GetFullName() );
409 wxString libPath = wxJoin( parts,
'/' );
413 wxString
name = parts.Last().substr( 0, parts.Last().length() - aExtensionLength );
418 wxLogTrace(
traceLibraries,
"Manager: Adding PCM lib '%s' as '%s'", libPath, nickname );
430 wxLogTrace(
traceLibraries,
"Manager: Not adding existing PCM lib '%s'", libPath );
455 return fn.GetFullPath();
466 return fn.GetFullPath();
474 return wxString::Format( wxS(
"${%s}/%s" ), templateDirVar,
tableFileName( aType ) );
488 auto it = common->m_Env.vars.find( templateDirVar );
490 if( it != common->m_Env.vars.end() && it->second.GetDefinedExternally() )
500 if( wxFileName fn( aPath ); fn.IsFileReadable() )
520 std::vector<LIBRARY_TABLE_TYPE> invalidTables;
530 invalidTables.emplace_back( tableType );
533 return invalidTables;
542 table.SetType( aType );
543 table.Rows().clear();
547 if( aPopulateDefaultLibraries && defaultLib.IsFileReadable() )
555 else if( aPopulateDefaultLibraries )
557 auto typeName = magic_enum::enum_name( aType );
558 wxLogTrace(
traceLibraries,
"No stock library table for %s at '%s'; creating empty global table",
559 wxString( typeName.data(), typeName.size() ), defaultLib.GetFullPath() );
565 table.Format( &formatter );
584 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
585 adapter->GlobalTablesChanged( aTablesToLoad );
597 wxCHECK( settings, );
605 wxFileName d( *packagesPath,
"" );
610 wxDir dir( d.GetPath() );
612 dir.Traverse( traverser );
616 table->Save().map_error(
619 wxLogTrace(
traceLibraries, wxT(
"Warning: save failed after PCM auto-add: %s" ),
626 auto cleanupRemovedPCMLibraries =
634 auto toErase = std::ranges::remove_if(
table->Rows(),
637 if( !IsPcmManagedRow( aRow ) )
640 wxString path = GetFullURI( &aRow, true );
641 return !wxFileName::Exists( path );
644 bool hadRemovals = !toErase.empty();
645 table->Rows().erase( toErase.begin(), toErase.end() );
649 table->Save().map_error(
652 wxLogTrace(
traceLibraries, wxT(
"Warning: save failed after PCM auto-remove: %s" ),
684 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
685 adapter->ProjectChanged();
693 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
694 adapter->AbortAsyncLoad();
699 std::unique_ptr<LIBRARY_MANAGER_ADAPTER>&& aAdapter )
703 wxCHECK_MSG( !
m_adapters.contains( aType ), ,
"You should only register an adapter once!" );
741 wxCHECK_MSG(
false, std::nullopt,
"Table() requires a single scope" );
748 magic_enum::enum_name( aType ) );
759 if( !
Project().IsNullProject() )
774 bool aIncludeInvalid )
const
776 std::map<wxString, LIBRARY_TABLE_ROW*> rows;
777 std::vector<wxString> rowOrder;
779 std::list<std::ranges::ref_view<const std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>>>> tables;
784 tables = { std::views::all(
m_tables ) };
799 std::function<void(
const std::unique_ptr<LIBRARY_TABLE>&,
bool parentHidden)> processTable =
800 [&](
const std::unique_ptr<LIBRARY_TABLE>& aTable,
const bool parentHidden )
802 if( aTable->Type() != aType )
805 if( aTable->IsOk() || aIncludeInvalid )
809 if( row.IsOk() || aIncludeInvalid )
813 row.SetHidden(
true );
828 if( !rows.contains( row.Nickname() ) )
829 rowOrder.emplace_back( row.Nickname() );
831 rows[ row.Nickname() ] = &row;
838 for(
const std::unique_ptr<LIBRARY_TABLE>&
table :
839 std::views::join( tables ) | std::views::values )
841 processTable(
table,
false );
844 std::vector<LIBRARY_TABLE_ROW*> ret;
846 for(
const wxString& row : rowOrder )
847 ret.emplace_back( rows[row] );
858 auto key = std::make_tuple( aType, aScope, aNickname );
866 if( row->Nickname() == aNickname )
869 m_rowCache[std::make_tuple( aType, aScope, aNickname )] = row;
879 const wxString& aUri,
895 if( std::optional<LIBRARY_MANAGER_ADAPTER*> adapter =
Adapter( aType ); adapter )
896 ( *adapter )->ReloadLibraryEntry( aNickname, aScope );
901 const wxString& aNickname )
903 if( std::optional<LIBRARY_MANAGER_ADAPTER*> adapter =
Adapter( aType ); adapter )
904 return ( *adapter )->LoadLibraryEntry( aNickname );
911 std::initializer_list<LIBRARY_TABLE_TYPE> aTablesToLoad )
920 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
921 adapter->ProjectTablesChanged( aTablesToLoad );
924 if( wxFileName::IsDirReadable( aProjectPath ) )
938 if( aTablesToLoad.size() == 0 )
948 wxLogTrace(
traceLibraries,
"New project path %s is not readable, not loading project tables", aProjectPath );
958 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
959 adapter->ProjectTablesReloaded( aTablesToLoad );
965 std::initializer_list<LIBRARY_TABLE_TYPE> aTablesToLoad )
982 if( std::optional<const LIBRARY_TABLE_ROW*>
result =
GetRow( aType, aNickname ) )
1004 path.MakeAbsolute();
1005 return path.GetFullPath();
1020 const wxString& uri = aRow.
URI();
1022 if( !uri.StartsWith( wxS(
"${" ) ) )
1025 size_t end = uri.find( wxS(
'}' ) );
1027 if(
end == wxString::npos ||
end <= 2 )
1030 wxString varName = uri.SubString( 2,
end - 1 );
1038 if(
end + 1 >= uri.length() || uri[
end + 1] != wxS(
'/' ) )
1045 wxArrayString parts = wxSplit( uri.Mid(
end + 2 ),
'/',
'\0' );
1047 if( parts.size() < 3 )
1050 for(
const wxString& part : parts )
1052 if( part.IsEmpty() )
1056 wxString category = parts[0];
1057 wxString leaf = parts.Last();
1062 auto hasLibExtension = [&leaf](
const wxString& aExt )
1064 return leaf.length() > aExt.length() && leaf.EndsWith( aExt );
1067 if( category == wxS(
"symbols" ) )
1068 return hasLibExtension( wxS(
".kicad_sym" ) );
1070 if( category == wxS(
"footprints" ) )
1071 return hasLibExtension( wxS(
".pretty" ) );
1073 if( category == wxS(
"design_blocks" ) )
1075 static const wxString designBlockExt =
1078 return hasLibExtension( designBlockExt );
1088 if( aURI1.Find(
"://" ) != wxNOT_FOUND )
1091 return aURI1 == aURI2;
1095 const wxFileName fn1( aURI1 );
1096 const wxFileName fn2( aURI2 );
1161 bool me = aChangedTables.size() == 0;
1165 if( type ==
Type() )
1194 if( it->second.global_owner ==
this )
1204 bool me = aChangedTables.size() == 0;
1208 if( type ==
Type() )
1223 std::initializer_list<LIBRARY_TABLE_TYPE> aChangedTables )
1225 bool me = aChangedTables.size() == 0;
1229 if( type ==
Type() )
1248 [
this](
const auto& aEntry )
1273 if( loadedRow->
URI() == aRow.
URI() && loadedRow->
Type() == aRow.
Type() )
1290 std::optional<LIB_STATUS> status =
CheckLibrary( &lib );
1292 if( status.has_value() )
1296 if( status.value().error.has_value() )
1307 aRow.
SetOk(
false );
1332 return row->Nickname();
1335 return std::nullopt;
1341 std::vector<wxString> ret;
1342 std::vector<LIBRARY_TABLE_ROW*> rows =
m_manager.Rows(
Type() );
1344 wxLogTrace(
traceLibraries,
"GetLibraryNames: checking %zu rows from table", rows.size() );
1348 wxString nickname = row->Nickname();
1349 std::optional<const LIB_DATA*> loaded =
fetchIfLoaded( nickname );
1352 ret.emplace_back( nickname );
1357 wxLogTrace(
traceLibraries,
"GetLibraryNames: returning %zu of %zu libraries", ret.size(), rows.size() );
1364 std::optional<const LIB_DATA*> r =
fetchIfLoaded( aNickname );
1367 return !aCheckEnabled || !r.value()->row->Disabled();
1382 std::lock_guard pluginGuard(
pluginMutex( aNickname ) );
1400 if( std::optional<const LIB_DATA*> optRow =
fetchIfLoaded( aNickname ); optRow )
1401 return ( *optRow )->row->Description();
1403 return std::nullopt;
1408 bool aIncludeInvalid )
const
1422 const wxString& aUri,
1459 return std::nullopt;
1462 return loaded /
static_cast<float>( total );
1468 wxLogTrace(
traceLibraries,
"BlockUntilLoaded: entry, acquiring m_loadMutex" );
1469 std::unique_lock<std::mutex> asyncLock(
m_loadMutex );
1473 for(
const std::future<void>& future :
m_futures )
1476 wxLogTrace(
traceLibraries,
"BlockUntilLoaded: all futures complete, loadCount=%zu, loadTotal=%zu",
1507 return it->second.status.error;
1514 return it->second.status.error;
1517 return std::nullopt;
1523 std::vector<std::pair<wxString, LIB_STATUS>> ret;
1527 if( row->Disabled() )
1532 ret.emplace_back( std::make_pair( row->Nickname(), *
result ) );
1542 ret.emplace_back( std::make_pair( row->Nickname(),
1553 std::vector<KI_ERROR> errors;
1559 wxString title = status.error->message.BeforeFirst(
'\n' );
1560 title.StartsWith( wxS(
"IO_ERROR: " ), &title );
1561 errors.emplace_back(
1563 .SetDescription( title )
1565 .SetDebugText( status.error->details )
1582 return std::nullopt;
1594 std::shared_mutex& aMutex )
1596 bool wasLoaded =
false;
1599 std::unique_lock lock( aMutex );
1600 auto it = aTarget.find( aNickname );
1602 if( it != aTarget.end() && it->second.plugin )
1605 aTarget.erase( it );
1617 else if( !
result.has_value() )
1619 wxLogTrace(
traceLibraries,
"ReloadLibraryEntry: failed to reload %s (%s): %s",
1620 aNickname, magic_enum::enum_name( aScopeToReload ),
1621 result.error().message );
1653 std::lock_guard pluginGuard(
pluginMutex( aNickname ) );
1670 std::lock_guard pluginGuard(
pluginMutex( aNickname ) );
1679 wxLogTrace(
traceLibraries,
"CreateLibrary: IO_ERROR for %s: %s",
1680 aNickname, ioe.
What() );
1683 catch(
const std::exception& e )
1685 wxLogTrace(
traceLibraries,
"CreateLibrary: std::exception for %s: %s",
1686 aNickname, e.what() );
1691 wxLogTrace(
traceLibraries,
"CreateLibrary: library row '%s' not found", aNickname );
1712 return std::nullopt;
1717 return std::nullopt;
1727 return std::nullopt;
1731 return std::nullopt;
1745 return std::nullopt;
1750 return std::nullopt;
1760 return std::nullopt;
1764 return std::nullopt;
1770 std::map<wxString, LIB_DATA>& aTarget,
1771 std::shared_mutex& aMutex )
1773 bool present =
false;
1776 std::shared_lock lock( aMutex );
1777 present = aTarget.contains( aNickname ) && aTarget.at( aNickname ).plugin;
1785 wxLogTrace(
traceLibraries,
"Library %s (%s) not yet loaded, will attempt...",
1786 aNickname, magic_enum::enum_name( aScope ) );
1790 std::unique_lock lock( aMutex );
1793 aTarget[ row->
Nickname() ].row = row;
1797 aTarget[ row->
Nickname() ].global_owner =
this;
1799 return &aTarget.at( aNickname );
1803 return tl::unexpected(
plugin.error() );
1810 std::shared_lock lock( aMutex );
1811 return &aTarget.at( aNickname );
1828 wxString msg = wxString::Format(
_(
"Library %s not found" ), aNickname );
1839 return it->second.status;
1846 return it->second.status;
1849 return std::nullopt;
1855 std::unique_lock<std::mutex> asyncLock(
m_loadMutex, std::try_to_lock );
1861 []( std::future<void>& aFuture )
1863 return aFuture.valid()
1864 && aFuture.wait_for( 0s ) == std::future_status::ready;
1869 wxLogTrace(
traceLibraries,
"Cannot AsyncLoad, futures from a previous call remain!" );
1873 std::vector<LIBRARY_TABLE_ROW*> rows =
m_manager.Rows(
Type() );
1880 wxLogTrace(
traceLibraries,
"AsyncLoad: no libraries left to load; exiting" );
1887 [&](
const wxString& aLib, std::map<wxString, LIB_DATA>& aMap, std::shared_mutex& aMutex )
1889 std::shared_lock lock( aMutex );
1891 if(
auto it = aMap.find( aLib ); it != aMap.end() )
1893 LOAD_STATUS status = it->second.status.load_status;
1911 auto workQueue = std::make_shared<std::vector<LOAD_WORK>>();
1912 workQueue->reserve( rows.size() );
1916 wxString nickname = row->Nickname();
1921 if( row->Disabled() )
1939 workQueue->emplace_back( LOAD_WORK{ nickname, scope,
getUri( row ) } );
1942 if( workQueue->empty() )
1944 wxLogTrace(
traceLibraries,
"AsyncLoad: all libraries already loaded; exiting" );
1951 size_t poolSize =
tp.get_thread_count();
1952 size_t maxLoadThreads = std::max<size_t>( 1, poolSize > 2 ? poolSize - 2 : 1 );
1953 size_t numWorkers = std::min( maxLoadThreads, workQueue->size() );
1955 auto workIndex = std::make_shared<std::atomic<size_t>>( 0 );
1957 wxLogTrace(
traceLibraries,
"AsyncLoad: %zu libraries to load, using %zu worker threads (pool has %zu)",
1958 workQueue->size(), numWorkers, poolSize );
1960 for(
size_t w = 0; w < numWorkers; ++w )
1963 [
this, workQueue, workIndex]()
1967 if( m_abort.load() )
1970 size_t idx = workIndex->fetch_add( 1 );
1972 if( idx >= workQueue->size() )
1975 const LOAD_WORK& work = ( *workQueue )[idx];
1976 LIBRARY_RESULT<LIB_DATA*> result = loadIfNeeded( work.nickname );
1978 if( result.has_value() )
1980 LIB_DATA* lib = *result;
1985 std::unique_lock lock(
1986 work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
1988 : m_librariesMutex );
1989 lib->status.load_status = LOAD_STATUS::LOADING;
1992 enumerateLibrary( lib, work.uri );
1995 std::unique_lock lock(
1996 work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
1998 : m_librariesMutex );
1999 lib->status.load_status = LOAD_STATUS::LOADED;
2002 catch( IO_ERROR& e )
2004 std::unique_lock lock(
2005 work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
2007 : m_librariesMutex );
2008 lib->status.load_status = LOAD_STATUS::LOAD_ERROR;
2009 lib->status.error = LIBRARY_ERROR( e.Problem(), e.Where() );
2010 wxLogTrace( traceLibraries,
"%s: plugin threw exception: %s",
2011 work.nickname, e.What() );
2016 std::unique_lock lock(
2017 work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
2019 : m_librariesMutex );
2021 std::map<wxString, LIB_DATA>& target =
2022 ( work.scope == LIBRARY_TABLE_SCOPE::GLOBAL ) ? globalLibs()
2025 target[work.nickname].status = LIB_STATUS( {
2026 .load_status = LOAD_STATUS::LOAD_ERROR,
2027 .error = result.error()
2037 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)
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
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().