24#include <magic_enum.hpp>
25#include <unordered_set>
54 std::vector<LIBRARY_TABLE_TYPE> aTablesToLoad )
68 wxCHECK_MSG(
false,
m_tables,
"Invalid scope passed to loadTables" );
72 std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>>& aTarget = getTarget();
74 if( aTablesToLoad.size() == 0 )
79 aTarget.erase( type );
83 if( fn.IsFileReadable() )
85 auto table = std::make_unique<LIBRARY_TABLE>( fn, aScope );
86 wxCHECK2(
table->Type() == type,
continue );
87 aTarget[type] = std::move(
table );
92 wxLogTrace(
traceLibraries,
"No library table found at %s", fn.GetFullPath() );
100 std::unordered_set<wxString> seenTables;
105 seenTables.insert( aTable.Path() );
117 file.MakeAbsolute( wxFileName( aTable.Path() ).GetPath() );
120 wxString src = file.GetFullPath();
122 if( seenTables.contains( src ) )
124 wxLogTrace(
traceLibraries,
"Library table %s has already been loaded!", src );
126 row.SetErrorDescription(
_(
"A reference to this library table already exists" ) );
130 auto child = std::make_unique<LIBRARY_TABLE>( file, aRootTable.
Scope() );
132 processOneTable( *child );
137 row.SetErrorDescription( child->ErrorDescription() );
145 processOneTable( aRootTable );
156 default: wxCHECK(
false, wxEmptyString );
165 wxCHECK( !
m_tables.contains( aType ), );
186 const wxString& aPrefix ) :
192 wxFileName f( aBasePath,
"" );
196 .value_or(
nullptr );
198 .value_or(
nullptr );
200 .value_or(
nullptr );
204 wxDirTraverseResult
OnFile(
const wxString& aFilePath )
override
206 wxFileName file = wxFileName::FileName( aFilePath );
210 if( file.GetExt() == wxT(
"kicad_sym" ) && file.GetDirCount() >=
m_prefix_dir_count + 2
216 return wxDIR_CONTINUE;
220 wxDirTraverseResult
OnDir(
const wxString& dirPath )
override
222 static wxString designBlockExt = wxString::Format( wxS(
".%s" ),
224 wxFileName dir = wxFileName::DirName( dirPath );
228 if( dirPath.EndsWith( wxS(
".pretty" ) ) && dir.GetDirCount() >=
m_prefix_dir_count + 3
233 else if( dirPath.EndsWith( designBlockExt )
240 return wxDIR_CONTINUE;
248 if( aTable->
HasRow( aNickname ) )
254 aNickname = wxString::Format(
"%s%s_%d",
m_lib_prefix, aBaseName, increment );
256 }
while( aTable->
HasRow( aNickname ) );
267 int aExtensionLength )
269 wxString versionedPath = wxString::Format( wxS(
"${%s}" ),
272 wxArrayString parts = aSource.GetDirs();
274 parts.Insert( versionedPath, 0 );
277 parts.Add( aSource.GetFullName() );
279 wxString libPath = wxJoin( parts,
'/' );
283 wxString
name = parts.Last().substr( 0, parts.Last().length() - aExtensionLength );
288 wxLogTrace(
traceLibraries,
"Manager: Adding PCM lib '%s' as '%s'", libPath, nickname );
300 wxLogTrace(
traceLibraries,
"Manager: Not adding existing PCM lib '%s'", libPath );
324 return fn.GetFullPath();
330 if( wxFileName fn( aPath ); fn.IsFileReadable() )
348 std::vector<LIBRARY_TABLE_TYPE> invalidTables;
356 invalidTables.emplace_back( tableType );
359 return invalidTables;
368 table.SetType( aType );
369 table.Rows().clear();
373 if( !defaultLib.IsFileReadable() )
375 wxLogTrace(
traceLibraries,
"Warning: couldn't read default library table for %s at '%s'",
376 magic_enum::enum_name( aType ), defaultLib.GetFullPath() );
379 if( aPopulateDefaultLibraries )
385 chained.
SetURI( defaultLib.GetFullPath() );
391 table.Format( &formatter );
409 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
410 adapter->GlobalTablesChanged( aTablesToLoad );
418 wxCHECK( settings, );
426 wxFileName d( *packagesPath,
"" );
431 wxDir dir( d.GetPath() );
433 dir.Traverse( traverser );
437 table->Save().map_error(
440 wxLogTrace(
traceLibraries,
"Warning: save failed after PCM auto-add: %s",
447 auto cleanupRemovedPCMLibraries =
453 auto toErase = std::ranges::remove_if(
table->Rows(),
456 wxString path = GetFullURI( &aRow, true );
457 return path.StartsWith( *packagesPath ) && !wxFile::Exists( path );
460 table->Rows().erase( toErase.begin(), toErase.end() );
462 if( !toErase.empty() )
464 table->Save().map_error(
468 "Warning: save failed after PCM auto-remove: %s",
489 for(
const std::unique_ptr<LIBRARY_MANAGER_ADAPTER>& adapter :
m_adapters | std::views::values )
490 adapter->ProjectChanged();
495 std::unique_ptr<LIBRARY_MANAGER_ADAPTER>&& aAdapter )
499 wxCHECK_MSG( !
m_adapters.contains( aType ), ,
"You should only register an adapter once!" );
523 wxCHECK_MSG(
false, std::nullopt,
"Table() requires a single scope" );
530 magic_enum::enum_name( aType ) );
558 bool aIncludeInvalid )
const
560 std::map<wxString, LIBRARY_TABLE_ROW*> rows;
561 std::vector<wxString> rowOrder;
563 std::list<std::ranges::ref_view<
564 const std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>>
570 tables = { std::views::all(
m_tables ) };
585 std::function<void(
const std::unique_ptr<LIBRARY_TABLE>&)> processTable =
586 [&](
const std::unique_ptr<LIBRARY_TABLE>& aTable )
588 if( aTable->Type() != aType )
591 if( aTable->IsOk() || aIncludeInvalid )
595 if( row.IsOk() || aIncludeInvalid )
606 if( !rows.contains( row.Nickname() ) )
607 rowOrder.emplace_back( row.Nickname() );
609 rows[ row.Nickname() ] = &row;
616 for(
const std::unique_ptr<LIBRARY_TABLE>&
table :
617 std::views::join( tables ) | std::views::values )
619 processTable(
table );
622 std::vector<LIBRARY_TABLE_ROW*> ret;
624 for(
const wxString& row : rowOrder )
625 ret.emplace_back( rows[row] );
632 const wxString& aNickname,
637 if( row->Nickname() == aNickname )
646 const wxString& aUri,
661 if( wxFileName::IsDirReadable( aProjectPath ) )
669 "New project path %s is not readable, not loading project tables",
676 const wxString& aNickname,
677 bool aSubstituted )
const
679 if( std::optional<const LIBRARY_TABLE_ROW*>
result =
GetRow( aType, aNickname ) )
700 return path.GetFullPath();
707 if( aURI1.Find(
"://" ) != wxNOT_FOUND )
710 return aURI1 == aURI2;
714 const wxFileName fn1( aURI1 );
715 const wxFileName fn2( aURI2 );
762 bool me = aChangedTables.size() == 0;
804 return row->Nickname();
813 std::vector<wxString> ret;
818 ret.emplace_back( row->Nickname() );
826 bool aCheckEnabled )
const
828 if( std::optional<const LIB_DATA*> r =
fetchIfLoaded( aNickname ); r.has_value() )
829 return !aCheckEnabled || !( *r )->row->Disabled();
858 if( std::optional<const LIB_DATA*> optRow =
fetchIfLoaded( aNickname ); optRow )
859 return ( *optRow )->row->Description();
880 const wxString& aUri,
916 for(
const std::future<void>& future :
m_futures )
938 std::vector<std::pair<wxString, LIB_STATUS>> ret;
944 ret.emplace_back( std::make_pair( row->Nickname(), *
result ) );
949 ret.emplace_back( std::make_pair( row->Nickname(),
LIB_STATUS( {
951 .error =
LIBRARY_ERROR(
_(
"Library not found in library table" ) )
1001 const wxString& aNickname )
const
1015 return std::nullopt;
1020 const wxString& aNickname )
1031 return std::nullopt;
1037 auto tryLoadFromScope =
1041 bool present =
false;
1044 std::lock_guard lock( aMutex );
1045 present = aTarget.contains( aNickname ) && aTarget.at( aNickname ).plugin;
1053 wxLogTrace(
traceLibraries,
"Library %s (%s) not yet loaded, will attempt...",
1054 aNickname, magic_enum::enum_name( aScope ) );
1058 std::lock_guard lock( aMutex );
1061 aTarget[ row->
Nickname() ].row = row;
1064 return &aTarget.at( aNickname );
1068 return tl::unexpected(
plugin.error() );
1075 return &aTarget.at( aNickname );
1089 wxString msg = wxString::Format(
_(
"Library %s not found" ), aNickname );
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::optional< float > AsyncLoadProgress() const
Returns async load progress between 0.0 and 1.0, or nullopt if load is not in progress.
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.
LIBRARY_TABLE * GlobalTable() const
Retrieves the global library table for this adapter type.
LIBRARY_MANAGER_ADAPTER(LIBRARY_MANAGER &aManager)
Constructs a type-specific adapter into the library manager.
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.
virtual std::map< wxString, LIB_DATA > & globalLibs()=0
virtual std::mutex & globalLibsMutex()=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
virtual std::optional< LIB_STATUS > GetLibraryStatus(const wxString &aNickname) const =0
Returns the status of a loaded library, or nullopt if the library hasn't been loaded (yet)
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.
std::vector< std::future< void > > m_futures
static wxString getUri(const LIBRARY_TABLE_ROW *aRow)
std::mutex m_libraries_mutex
bool CreateLibrary(const wxString &aNickname)
Creates the library (i.e. saves to disk) for the given row if it exists.
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_loadCount
LIBRARY_MANAGER & m_manager
std::optional< const LIB_DATA * > fetchIfLoaded(const wxString &aNickname) const
static wxString ExpandURI(const wxString &aShortURI, const PROJECT &aProject)
std::optional< LIBRARY_MANAGER_ADAPTER * > Adapter(LIBRARY_TABLE_TYPE aType) const
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)
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 RegisterAdapter(LIBRARY_TABLE_TYPE aType, std::unique_ptr< LIBRARY_MANAGER_ADAPTER > &&aAdapter)
static wxString DefaultGlobalTablePath(LIBRARY_TABLE_TYPE aType)
static std::vector< LIBRARY_TABLE_TYPE > InvalidGlobalTables()
void createEmptyTable(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope)
static bool GlobalTablesValid()
std::map< LIBRARY_TABLE_TYPE, std::unique_ptr< LIBRARY_TABLE > > m_projectTables
void LoadProjectTables(const wxString &aProjectPath)
std::optional< LIBRARY_TABLE_ROW * > FindRowByURI(LIBRARY_TABLE_TYPE aType, const wxString &aUri, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
static bool CreateGlobalTable(LIBRARY_TABLE_TYPE aType, bool aPopulateDefaultLibraries)
void loadTables(const wxString &aTablePath, LIBRARY_TABLE_SCOPE aScope, std::vector< LIBRARY_TABLE_TYPE > aTablesToLoad={})
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false) const
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
static wxString tableFileName(LIBRARY_TABLE_TYPE aType)
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
void ProjectChanged()
Notify all adapters that the project has changed.
static bool IsTableValid(const wxString &aPath)
std::map< LIBRARY_TABLE_TYPE, std::unique_ptr< LIBRARY_MANAGER_ADAPTER > > m_adapters
std::optional< LIBRARY_TABLE_ROW * > GetRow(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
void SetNickname(const wxString &aNickname)
void SetType(const wxString &aType)
std::map< std::string, UTF8 > GetOptionsMap() const
void SetDescription(const wxString &aDescription)
static const wxString TABLE_TYPE_NAME
void SetURI(const wxString &aUri)
const wxString & URI() const
const wxString & Nickname() const
LIBRARY_TABLE_ROW & InsertRow()
Builds a new row and inserts it at the end of the table; returning a reference to the row.
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.
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.
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
tl::expected< ResultType, LIBRARY_ERROR > LIBRARY_RESULT
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.
SETTINGS_MANAGER * GetSettingsManager()
PGM_BASE & Pgm()
The global program "get" accessor.
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.
wxLogTrace helper definitions.
Definition of file extensions used in Kicad.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().