KiCad PCB EDA Suite
PCM_TASK_MANAGER Class Reference

Helper class that handles package (un)installation. More...

#include <pcm_task_manager.h>

Public Member Functions

 PCM_TASK_MANAGER (std::shared_ptr< PLUGIN_CONTENT_MANAGER > pcm)
 
void DownloadAndInstall (const PCM_PACKAGE &aPackage, const wxString &aVersion, const wxString &aRepositoryId, const bool isUpdate)
 Enqueue package download and installation. More...
 
void Uninstall (const PCM_PACKAGE &aPackage)
 Enqueue package uninstallation. More...
 
void RunQueue (wxWindow *aParent)
 Run queue of pending actions. More...
 
void InstallFromFile (wxWindow *aParent, const wxString &aFilePath)
 Installs package from an archive file on disk. More...
 
bool ColorSettingsChanged () const
 

Private Member Functions

int downloadFile (const wxString &aFilePath, const wxString &aUrl)
 Download URL to a file. More...
 
void installDownloadedPackage (const PCM_PACKAGE &aPackage, const wxString &aVersion, const wxString &aRepositoryId, const wxFileName &aFilePath, const bool isUpdate)
 Installs downloaded package archive. More...
 
bool extract (const wxString &aFilePath, const wxString &aPackageId, bool isMultiThreaded)
 Extract package archive. More...
 
void deletePackageDirectories (const wxString &aPackageId, const std::forward_list< wxRegEx > &aKeep={})
 Delete all package files. More...
 

Private Attributes

std::unique_ptr< DIALOG_PCM_PROGRESSm_reporter
 
SYNC_QUEUE< PCM_TASKm_download_queue
 
SYNC_QUEUE< PCM_TASKm_install_queue
 
std::shared_ptr< PLUGIN_CONTENT_MANAGERm_pcm
 
std::atomic_bool m_color_themes_changed
 

Detailed Description

Helper class that handles package (un)installation.

Package state changes are first enqueued using DownloadAndInstall/Uninstall methods and then applied using RunQueue().

RunQueue() is multithreaded for better experience.

Definition at line 50 of file pcm_task_manager.h.

Constructor & Destructor Documentation

◆ PCM_TASK_MANAGER()

PCM_TASK_MANAGER::PCM_TASK_MANAGER ( std::shared_ptr< PLUGIN_CONTENT_MANAGER pcm)
inline

Definition at line 53 of file pcm_task_manager.h.

53: m_pcm( pcm ){};
std::shared_ptr< PLUGIN_CONTENT_MANAGER > m_pcm

Member Function Documentation

◆ ColorSettingsChanged()

bool PCM_TASK_MANAGER::ColorSettingsChanged ( ) const
Returns
true if color settings were installed or uninstalled by the most recent action

Definition at line 655 of file pcm_task_manager.cpp.

656{
657 return m_color_themes_changed.load();
658}
std::atomic_bool m_color_themes_changed

References m_color_themes_changed.

Referenced by DIALOG_PCM::OnApplyChangesClicked(), and DIALOG_PCM::OnInstallFromFileClicked().

◆ deletePackageDirectories()

void PCM_TASK_MANAGER::deletePackageDirectories ( const wxString &  aPackageId,
const std::forward_list< wxRegEx > &  aKeep = {} 
)
private

Delete all package files.

Parameters
aPackageIdid of the package
aKeeplist of regex indicating which files should not be deleted

Definition at line 464 of file pcm_task_manager.cpp.

466{
467 // Namespace delimiter changed on disk to allow flat loading of Python modules
468 wxString clean_package_id = aPackageId;
469 clean_package_id.Replace( '.', '_' );
470
471 int path_prefix_len = m_pcm->Get3rdPartyPath().Length();
472
473 auto sort_func = []( const wxString& a, const wxString& b )
474 {
475 if( a.length() > b.length() )
476 return true;
477 if( a.length() < b.length() )
478 return false;
479
480 if( a != b )
481 return a < b;
482
483 return false;
484 };
485
486 for( const wxString& dir : PCM_PACKAGE_DIRECTORIES )
487 {
488 wxFileName d( m_pcm->Get3rdPartyPath(), "" );
489 d.AppendDir( dir );
490 d.AppendDir( clean_package_id );
491
492 if( !d.DirExists() )
493 continue;
494
495 m_reporter->PCMReport( wxString::Format( _( "Removing directory %s" ), d.GetPath() ),
497
498 if( aKeep.empty() )
499 {
500 if( !d.Rmdir( wxPATH_RMDIR_RECURSIVE ) )
501 {
502 m_reporter->PCMReport(
503 wxString::Format( _( "Failed to remove directory %s" ), d.GetPath() ),
505 }
506 }
507 else
508 {
509 std::vector<wxString> files;
510 std::vector<wxString> dirs;
511 PATH_COLLECTOR collector( files, dirs );
512
513 wxDir( d.GetFullPath() )
514 .Traverse( collector, wxEmptyString, wxDIR_DEFAULT | wxDIR_NO_FOLLOW );
515
516 // Do a poor mans post order traversal by sorting paths in reverse length order
517 std::sort( files.begin(), files.end(), sort_func );
518 std::sort( dirs.begin(), dirs.end(), sort_func );
519
520 // Delete files that don't match any of the aKeep regexs
521 for( const wxString& file : files )
522 {
523 bool del = true;
524
525 for( const wxRegEx& re : aKeep )
526 {
527 wxString tmp = file.Mid( path_prefix_len );
528 tmp.Replace( "\\", "/" );
529
530 if( re.Matches( tmp ) )
531 {
532 // m_reporter->PCMReport( wxString::Format( _( "Keeping file '%s'." ), tmp ),
533 // RPT_SEVERITY_INFO );
534
535 del = false;
536 break;
537 }
538 }
539
540 if( del )
541 wxRemoveFile( file );
542 }
543
544 // Delete any empty dirs
545 for( const wxString& empty_dir : dirs )
546 {
547 wxFileName dname( empty_dir, "" );
548 dname.Rmdir(); // not passing any flags here will only remove empty directories
549 }
550 }
551 }
552}
std::unique_ptr< DIALOG_PCM_PROGRESS > m_reporter
#define _(s)
const std::unordered_set< wxString > PCM_PACKAGE_DIRECTORIES({ "plugins", "footprints", "3dmodels", "symbols", "resources", "colors", })
< Contains list of all valid directories that get extracted from a package archive
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_INFO

References _, Format(), m_pcm, m_reporter, PCM_PACKAGE_DIRECTORIES(), RPT_SEVERITY_ERROR, and RPT_SEVERITY_INFO.

Referenced by installDownloadedPackage(), InstallFromFile(), and Uninstall().

◆ DownloadAndInstall()

void PCM_TASK_MANAGER::DownloadAndInstall ( const PCM_PACKAGE aPackage,
const wxString &  aVersion,
const wxString &  aRepositoryId,
const bool  isUpdate 
)

Enqueue package download and installation.

Enqueues a download task for a given package version.

Download task fetches the package archive and if successful enqueues an installation task. Installation task verifies sha256 hash if specified, extracts the package, removes the downloaded archive and marks package as installed.

Both tasks report their state independently to a progress dialog.

Parameters
aPackagepackage metadata
aVersionversion to be installed
aRepositoryIdid of the source repository

Definition at line 57 of file pcm_task_manager.cpp.

59{
60 PCM_TASK download_task = [aPackage, aVersion, aRepositoryId, isUpdate, this]()
61 {
62 wxFileName file_path( PATHS::GetUserCachePath(), "" );
63 file_path.AppendDir( "pcm" );
64 file_path.SetFullName( wxString::Format( "%s_v%s.zip", aPackage.identifier, aVersion ) );
65
66 auto find_pkgver = std::find_if( aPackage.versions.begin(), aPackage.versions.end(),
67 [&aVersion]( const PACKAGE_VERSION& pv )
68 {
69 return pv.version == aVersion;
70 } );
71
72 if( find_pkgver == aPackage.versions.end() )
73 {
74 m_reporter->PCMReport( wxString::Format( _( "Version %s of package %s not found!" ),
75 aVersion, aPackage.identifier ),
77 return;
78 }
79
80 if( !wxDirExists( file_path.GetPath() )
81 && !wxFileName::Mkdir( file_path.GetPath(), wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
82 {
83 m_reporter->PCMReport( _( "Unable to create download directory!" ),
85 return;
86 }
87
88 int code = downloadFile( file_path.GetFullPath(), *find_pkgver->download_url );
89
90 if( code != CURLE_OK )
91 {
92 // Cleanup after ourselves and exit
93 wxRemoveFile( file_path.GetFullPath() );
94 return;
95 }
96
97 PCM_TASK install_task = [aPackage, aVersion, aRepositoryId, file_path, isUpdate, this]()
98 {
99 installDownloadedPackage( aPackage, aVersion, aRepositoryId, file_path, isUpdate );
100 };
101
102 m_install_queue.push( install_task );
103 };
104
105 m_download_queue.push( download_task );
106}
static wxString GetUserCachePath()
Gets the stock (install) 3d viewer plugins path.
Definition: paths.cpp:321
SYNC_QUEUE< PCM_TASK > m_install_queue
SYNC_QUEUE< PCM_TASK > m_download_queue
int downloadFile(const wxString &aFilePath, const wxString &aUrl)
Download URL to a file.
void installDownloadedPackage(const PCM_PACKAGE &aPackage, const wxString &aVersion, const wxString &aRepositoryId, const wxFileName &aFilePath, const bool isUpdate)
Installs downloaded package archive.
void push(T const &aValue)
Push a value onto the queue.
Definition: sync_queue.h:41
std::function< void()> PCM_TASK
< Package version metadata Package metadata
Definition: pcm_data.h:74
wxString identifier
Definition: pcm_data.h:99
std::vector< PACKAGE_VERSION > versions
Definition: pcm_data.h:107

References _, downloadFile(), Format(), PATHS::GetUserCachePath(), PCM_PACKAGE::identifier, installDownloadedPackage(), m_download_queue, m_install_queue, m_reporter, SYNC_QUEUE< T >::push(), RPT_SEVERITY_ERROR, and PCM_PACKAGE::versions.

Referenced by DIALOG_PCM::OnApplyChangesClicked().

◆ downloadFile()

int PCM_TASK_MANAGER::downloadFile ( const wxString &  aFilePath,
const wxString &  aUrl 
)
private

Download URL to a file.

Parameters
aFilePathpath to file
aUrlURL to download
Returns
int CURLE error code

Definition at line 109 of file pcm_task_manager.cpp.

110{
111 TRANSFER_CALLBACK callback = [&]( size_t dltotal, size_t dlnow, size_t ultotal, size_t ulnow )
112 {
113 if( dltotal > 1024 )
114 m_reporter->SetDownloadProgress( dlnow, dltotal );
115 else
116 m_reporter->SetDownloadProgress( 0.0, 0.0 );
117
118 return m_reporter->IsCancelled();
119 };
120
121 std::ofstream out( aFilePath.ToUTF8(), std::ofstream::binary );
122
123 KICAD_CURL_EASY curl;
124 curl.SetOutputStream( &out );
125 curl.SetURL( url.ToUTF8().data() );
126 curl.SetFollowRedirects( true );
127 curl.SetTransferCallback( callback, 250000L );
128
129 m_reporter->PCMReport( wxString::Format( _( "Downloading package url: '%s'" ), url ),
131
132 int code = curl.Perform();
133
134 out.close();
135
136 uint64_t download_total;
137
138 if( CURLE_OK == curl.GetTransferTotal( download_total ) )
139 m_reporter->SetDownloadProgress( download_total, download_total );
140
141 if( code != CURLE_OK && code != CURLE_ABORTED_BY_CALLBACK )
142 {
143 m_reporter->PCMReport( wxString::Format( _( "Failed to download url %s\n%s" ), url,
144 curl.GetErrorText( code ) ),
146 }
147
148 return code;
149}
int Perform()
Equivalent to curl_easy_perform.
bool SetTransferCallback(const TRANSFER_CALLBACK &aCallback, size_t aInterval)
bool SetURL(const std::string &aURL)
Set the request URL.
bool SetFollowRedirects(bool aFollow)
Enable the following of HTTP(s) and other redirects, by default curl does not follow redirects.
int GetTransferTotal(uint64_t &aDownloadedBytes) const
bool SetOutputStream(const std::ostream *aOutput)
const std::string GetErrorText(int aCode)
Fetch CURL's "friendly" error string for a given error code.
std::function< int(size_t, size_t, size_t, size_t)> TRANSFER_CALLBACK
Wrapper interface around the curl_easy API/.

References _, Format(), KICAD_CURL_EASY::GetErrorText(), KICAD_CURL_EASY::GetTransferTotal(), m_reporter, KICAD_CURL_EASY::Perform(), RPT_SEVERITY_ERROR, RPT_SEVERITY_INFO, KICAD_CURL_EASY::SetFollowRedirects(), KICAD_CURL_EASY::SetOutputStream(), KICAD_CURL_EASY::SetTransferCallback(), and KICAD_CURL_EASY::SetURL().

Referenced by DownloadAndInstall().

◆ extract()

bool PCM_TASK_MANAGER::extract ( const wxString &  aFilePath,
const wxString &  aPackageId,
bool  isMultiThreaded 
)
private

Extract package archive.

Parameters
aFilePathpath to the archive
aPackageIdid of the package
isMultiThreadedMUST be set to true if the caller is not running in the main thread
Returns
true if archive was extracted successfuly

Definition at line 235 of file pcm_task_manager.cpp.

237{
238 wxFFileInputStream stream( aFilePath );
239 wxZipInputStream zip( stream );
240
241 wxLogNull no_wx_logging;
242
243 int entries = zip.GetTotalEntries();
244 int extracted = 0;
245
246 wxArchiveEntry* entry = zip.GetNextEntry();
247
248 if( !zip.IsOk() )
249 {
250 m_reporter->PCMReport( _( "Error extracting file!" ), RPT_SEVERITY_ERROR );
251 return false;
252 }
253
254 // Namespace delimiter changed on disk to allow flat loading of Python modules
255 wxString clean_package_id = aPackageId;
256 clean_package_id.Replace( '.', '_' );
257
258 for( ; entry; entry = zip.GetNextEntry() )
259 {
260 wxArrayString path_parts =
261 wxSplit( entry->GetName(), wxFileName::GetPathSeparator(), (wxChar) 0 );
262
263 if( path_parts.size() < 2
264 || PCM_PACKAGE_DIRECTORIES.find( path_parts[0] ) == PCM_PACKAGE_DIRECTORIES.end()
265 || path_parts[path_parts.size() - 1].IsEmpty() )
266 {
267 // Ignore files in the root of the archive and files outside of package dirs.
268 continue;
269 }
270
271 // m_reporter->Report( wxString::Format( _( "Extracting file '%s'\n" ), entry->GetName() ),
272 // RPT_SEVERITY_INFO );
273
274 // Transform paths from
275 // <PackageRoot>/$folder/$contents
276 // To
277 // $KICAD7_3RD_PARTY/$folder/$package_id/$contents
278 path_parts.Insert( clean_package_id, 1 );
279 path_parts.Insert( m_pcm->Get3rdPartyPath(), 0 );
280
281 wxString fullname = wxJoin( path_parts, wxFileName::GetPathSeparator(), (wxChar) 0 );
282
283 // Ensure the target directory exists and create it if not.
284 wxString t_path = wxPathOnly( fullname );
285
286 if( !wxDirExists( t_path ) )
287 {
288 wxFileName::Mkdir( t_path, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
289 }
290
291 wxTempFileOutputStream out( fullname );
292
293 if( !( CopyStreamData( zip, out, entry->GetSize() ) && out.Commit() ) )
294 {
295 m_reporter->PCMReport( _( "Error extracting file!" ), RPT_SEVERITY_ERROR );
296 return false;
297 }
298
299 extracted++;
300 m_reporter->SetPackageProgress( extracted, entries );
301
302 if( !isMultiThreaded )
303 m_reporter->KeepRefreshing( false );
304
305 if( m_reporter->IsCancelled() )
306 break;
307 }
308
309 zip.CloseEntry();
310
311 if( m_reporter->IsCancelled() )
312 {
313 m_reporter->PCMReport( _( "Aborting package installation." ), RPT_SEVERITY_INFO );
314 return false;
315 }
316
317 m_reporter->PCMReport( _( "Extracted package\n" ), RPT_SEVERITY_INFO );
318 m_reporter->SetPackageProgress( entries, entries );
319
320 return true;
321}
static bool CopyStreamData(wxInputStream &inputStream, wxOutputStream &outputStream, wxFileOffset size)

References _, CopyStreamData(), m_pcm, m_reporter, PCM_PACKAGE_DIRECTORIES(), RPT_SEVERITY_ERROR, RPT_SEVERITY_INFO, and zip.

Referenced by installDownloadedPackage(), and InstallFromFile().

◆ installDownloadedPackage()

void PCM_TASK_MANAGER::installDownloadedPackage ( const PCM_PACKAGE aPackage,
const wxString &  aVersion,
const wxString &  aRepositoryId,
const wxFileName &  aFilePath,
const bool  isUpdate 
)
private

Installs downloaded package archive.

Parameters
aPackagepackage metadata
aVersionversion to be installed
aRepositoryIdid of the source repository
aFilePathpath to the archive
isUpdatetrue if this is an update operation

Definition at line 152 of file pcm_task_manager.cpp.

156{
157 auto pkgver = std::find_if( aPackage.versions.begin(), aPackage.versions.end(),
158 [&aVersion]( const PACKAGE_VERSION& pv )
159 {
160 return pv.version == aVersion;
161 } );
162
163 if( pkgver == aPackage.versions.end() )
164 {
165 m_reporter->PCMReport( wxString::Format( _( "Version %s of package %s not found!" ),
166 aVersion, aPackage.identifier ),
168 return;
169 }
170
171 // wxRegEx is not CopyConstructible hence the weird choice of forward_list
172 std::forward_list<wxRegEx> keep_on_update;
173
174 if( isUpdate )
175 compile_keep_on_update_regex( aPackage, *pkgver, keep_on_update );
176
177 const std::optional<wxString>& hash = pkgver->download_sha256;
178 bool hash_match = true;
179
180 if( hash )
181 {
182 std::ifstream stream( aFilePath.GetFullPath().ToUTF8(), std::ios::binary );
183 hash_match = m_pcm->VerifyHash( stream, *hash );
184 }
185
186 if( !hash_match )
187 {
188 m_reporter->PCMReport( wxString::Format( _( "Downloaded archive hash for package "
189 "%s does not match repository entry. "
190 "This may indicate a problem with the "
191 "package, if the issue persists "
192 "report this to repository maintainers." ),
193 aPackage.identifier ),
195 }
196 else
197 {
198 if( isUpdate )
199 {
200 m_reporter->PCMReport(
201 wxString::Format( _( "Removing previous version of package '%s'." ),
202 aPackage.identifier ),
204
205 deletePackageDirectories( aPackage.identifier, keep_on_update );
206 }
207
208 m_reporter->PCMReport(
209 wxString::Format( _( "Extracting package '%s'." ), aPackage.identifier ),
211
212 if( extract( aFilePath.GetFullPath(), aPackage.identifier, true ) )
213 {
214 m_pcm->MarkInstalled( aPackage, pkgver->version, aRepositoryId );
215 // TODO register libraries.
216 }
217 else
218 {
219 // Cleanup possibly partially extracted package
221 }
222 }
223
224 if( aPackage.type == PCM_PACKAGE_TYPE::PT_COLORTHEME )
225 m_color_themes_changed.store( true );
226
227 m_reporter->PCMReport(
228 wxString::Format( _( "Removing downloaded archive '%s'." ), aFilePath.GetFullName() ),
230
231 wxRemoveFile( aFilePath.GetFullPath() );
232}
void deletePackageDirectories(const wxString &aPackageId, const std::forward_list< wxRegEx > &aKeep={})
Delete all package files.
bool extract(const wxString &aFilePath, const wxString &aPackageId, bool isMultiThreaded)
Extract package archive.
@ PT_COLORTHEME
Definition: pcm_data.h:45
void compile_keep_on_update_regex(const PCM_PACKAGE &pkg, const PACKAGE_VERSION &ver, std::forward_list< wxRegEx > &aKeepOnUpdate)
PCM_PACKAGE_TYPE type
Definition: pcm_data.h:100

References _, compile_keep_on_update_regex(), deletePackageDirectories(), extract(), Format(), PCM_PACKAGE::identifier, m_color_themes_changed, m_pcm, m_reporter, PT_COLORTHEME, RPT_SEVERITY_ERROR, RPT_SEVERITY_INFO, PCM_PACKAGE::type, and PCM_PACKAGE::versions.

Referenced by DownloadAndInstall().

◆ InstallFromFile()

void PCM_TASK_MANAGER::InstallFromFile ( wxWindow *  aParent,
const wxString &  aFilePath 
)

Installs package from an archive file on disk.

Unlike DownloadAndInstall/Uninstall methods this one immediately extracts the package and marks it as installed.

Parameters
aParentparent dialog for progress window
aFilePathpath to the archive file

Definition at line 324 of file pcm_task_manager.cpp.

325{
326 wxFFileInputStream stream( aFilePath );
327
328 if( !stream.IsOk() )
329 {
330 wxLogError( _( "Could not open archive file." ) );
331 return;
332 }
333
334 wxZipInputStream zip( stream );
335
336 if( !zip.IsOk() )
337 {
338 wxLogError( _( "Invalid archive file format." ) );
339 return;
340 }
341
342 nlohmann::json metadata;
343
344 for( wxArchiveEntry* entry = zip.GetNextEntry(); entry != nullptr; entry = zip.GetNextEntry() )
345 {
346 // Find and load metadata.json
347 if( entry->GetName() != "metadata.json" )
348 continue;
349
350 wxStringOutputStream strStream;
351
352 if( CopyStreamData( zip, strStream, entry->GetSize() ) )
353 {
354 try
355 {
356 metadata = nlohmann::json::parse( strStream.GetString().ToUTF8().data() );
357 m_pcm->ValidateJson( metadata );
358 }
359 catch( const std::exception& e )
360 {
361 wxLogError( wxString::Format( _( "Unable to parse package metadata:\n\n%s" ),
362 e.what() ) );
363 break;
364 }
365 }
366 }
367
368 if( metadata.empty() )
369 {
370 wxLogError( _( "Archive does not contain a valid metadata.json file" ) );
371 return;
372 }
373
374 PCM_PACKAGE package = metadata.get<PCM_PACKAGE>();
375
376 if( package.versions.size() != 1 )
377 {
378 wxLogError( _( "Archive metadata must have a single version defined" ) );
379 return;
380 }
381
382 bool isUpdate = false;
383 // wxRegEx is not CopyConstructible hence the weird choice of forward_list
384 std::forward_list<wxRegEx> keep_on_update;
385 const std::vector<PCM_INSTALLATION_ENTRY> installed_packages = m_pcm->GetInstalledPackages();
386
387 if( std::find_if( installed_packages.begin(), installed_packages.end(),
388 [&]( const PCM_INSTALLATION_ENTRY& entry )
389 {
390 return entry.package.identifier == package.identifier;
391 } )
392 != installed_packages.end() )
393 {
394 if( wxMessageBox(
396 _( "Package with identifier %s is already installed. "
397 "Would you like to update it to the version from selected file?" ),
398 package.identifier ),
399 _( "Update package" ), wxICON_EXCLAMATION | wxYES_NO, aParent )
400 == wxNO )
401 return;
402
403 isUpdate = true;
404
405 compile_keep_on_update_regex( package, package.versions[0], keep_on_update );
406 }
407
408 m_reporter = std::make_unique<DIALOG_PCM_PROGRESS>( aParent, false );
409#ifdef __WXMAC__
410 m_reporter->ShowWindowModal();
411#else
412 m_reporter->Show();
413#endif
414
415 if( isUpdate )
416 {
417 m_reporter->PCMReport( wxString::Format( _( "Removing previous version of package '%s'." ),
418 package.identifier ),
420
421 deletePackageDirectories( package.identifier, keep_on_update );
422 }
423
424 if( extract( aFilePath, package.identifier, false ) )
425 m_pcm->MarkInstalled( package, package.versions[0].version, "" );
426
427 m_reporter->SetFinished();
428 m_reporter->KeepRefreshing( false );
429 m_reporter->Destroy();
430 m_reporter.reset();
431
432 aParent->Raise();
433
435}
nlohmann::json json
Definition: gerbview.cpp:44
bool parse(std::istream &aStream, bool aVerbose)
Parse a PCB or footprint file from the given input stream.
Definition: pcm_data.h:138
Repository reference to a resource.
Definition: pcm_data.h:95

References _, compile_keep_on_update_regex(), CopyStreamData(), deletePackageDirectories(), extract(), Format(), m_color_themes_changed, m_pcm, m_reporter, parse(), PT_COLORTHEME, RPT_SEVERITY_INFO, and zip.

Referenced by DIALOG_PCM::OnInstallFromFileClicked().

◆ RunQueue()

void PCM_TASK_MANAGER::RunQueue ( wxWindow *  aParent)

Run queue of pending actions.

This method spawns 2 threads to concurrently run tasks in download and install queues until they are drained.

Download queue feeds into install queue so the install thread keeps running until download thread indicated that it's finished AND all installs are processed.

Parameters
aParentparent dialog for progress window

Definition at line 575 of file pcm_task_manager.cpp.

576{
577 m_reporter = std::make_unique<DIALOG_PCM_PROGRESS>( aParent );
578
579 m_reporter->SetNumPhases( m_download_queue.size() + m_install_queue.size() );
580#ifdef __WXMAC__
581 m_reporter->ShowWindowModal();
582#else
583 m_reporter->Show();
584#endif
585
586 wxSafeYield();
587
588 std::mutex mutex;
589 std::condition_variable condvar;
590 bool download_complete = false;
591
592 m_color_themes_changed.store( false );
593
594 std::thread download_thread(
595 [&]()
596 {
597 while( !m_download_queue.empty() && !m_reporter->IsCancelled() )
598 {
599 PCM_TASK task;
600 m_download_queue.pop( task );
601 task();
602 condvar.notify_all();
603 }
604
605 std::unique_lock<std::mutex> lock( mutex );
606 download_complete = true;
607 condvar.notify_all();
608 } );
609
610 std::thread install_thread(
611 [&]()
612 {
613 std::unique_lock<std::mutex> lock( mutex );
614
615 do
616 {
617 condvar.wait( lock,
618 [&]()
619 {
620 return download_complete || !m_install_queue.empty()
621 || m_reporter->IsCancelled();
622 } );
623
624 lock.unlock();
625
626 while( !m_install_queue.empty() && !m_reporter->IsCancelled() )
627 {
628 PCM_TASK task;
629 m_install_queue.pop( task );
630 task();
631 m_reporter->AdvancePhase();
632 }
633
634 lock.lock();
635
636 } while( ( !m_install_queue.empty() || !download_complete )
637 && !m_reporter->IsCancelled() );
638
639 m_reporter->PCMReport( _( "Done." ), RPT_SEVERITY_INFO );
640
641 m_reporter->SetFinished();
642 } );
643
644 m_reporter->KeepRefreshing( true );
645 m_reporter->Destroy();
646 m_reporter.reset();
647
648 aParent->Raise();
649
650 download_thread.join();
651 install_thread.join();
652}
bool pop(T &aReceiver)
Pop a value if the queue into the provided variable.
Definition: sync_queue.h:63
bool empty() const
Return true if the queue is empty.
Definition: sync_queue.h:82
size_t size() const
Return the size of the queue.
Definition: sync_queue.h:91

References _, SYNC_QUEUE< T >::empty(), m_color_themes_changed, m_download_queue, m_install_queue, m_reporter, SYNC_QUEUE< T >::pop(), RPT_SEVERITY_INFO, and SYNC_QUEUE< T >::size().

Referenced by DIALOG_PCM::OnApplyChangesClicked().

◆ Uninstall()

void PCM_TASK_MANAGER::Uninstall ( const PCM_PACKAGE aPackage)

Enqueue package uninstallation.

Enqueues uninstallation task that removes all package files and marks package as uninstalled.

Parameters
aPackagepackage metadata

Definition at line 555 of file pcm_task_manager.cpp.

556{
557 PCM_TASK task = [aPackage, this]
558 {
560
561 m_pcm->MarkUninstalled( aPackage );
562
563 if( aPackage.type == PCM_PACKAGE_TYPE::PT_COLORTHEME )
564 m_color_themes_changed.store( true );
565
566 m_reporter->PCMReport(
567 wxString::Format( _( "Package %s uninstalled" ), aPackage.identifier ),
569 };
570
571 m_install_queue.push( task );
572}

References _, deletePackageDirectories(), Format(), PCM_PACKAGE::identifier, m_color_themes_changed, m_install_queue, m_pcm, m_reporter, PT_COLORTHEME, SYNC_QUEUE< T >::push(), RPT_SEVERITY_INFO, and PCM_PACKAGE::type.

Referenced by DIALOG_PCM::OnApplyChangesClicked().

Member Data Documentation

◆ m_color_themes_changed

std::atomic_bool PCM_TASK_MANAGER::m_color_themes_changed
private

◆ m_download_queue

SYNC_QUEUE<PCM_TASK> PCM_TASK_MANAGER::m_download_queue
private

Definition at line 155 of file pcm_task_manager.h.

Referenced by DownloadAndInstall(), and RunQueue().

◆ m_install_queue

SYNC_QUEUE<PCM_TASK> PCM_TASK_MANAGER::m_install_queue
private

Definition at line 156 of file pcm_task_manager.h.

Referenced by DownloadAndInstall(), RunQueue(), and Uninstall().

◆ m_pcm

std::shared_ptr<PLUGIN_CONTENT_MANAGER> PCM_TASK_MANAGER::m_pcm
private

◆ m_reporter

std::unique_ptr<DIALOG_PCM_PROGRESS> PCM_TASK_MANAGER::m_reporter
private

The documentation for this class was generated from the following files: