Progress reporting for Run Jobs.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19629

(cherry picked from commit 0464cc18b1bf724a8776653c928ed75343392114)
This commit is contained in:
Jeff Young 2025-06-28 21:30:24 -06:00
parent d38bd7e1a6
commit 6c6ef1cf5d
13 changed files with 199 additions and 151 deletions

View File

@ -42,22 +42,20 @@ void JOB_DISPATCHER::Register( const std::string& aJobTypeName,
}
int JOB_DISPATCHER::RunJob( JOB* job, REPORTER* aReporter )
int JOB_DISPATCHER::RunJob( JOB* job, REPORTER* aReporter, PROGRESS_REPORTER* aProgressReporter )
{
int result = CLI::EXIT_CODES::ERR_UNKNOWN;
REPORTER* existingReporter = m_reporter;
if( aReporter )
{
m_reporter = aReporter;
}
m_progressReporter = aProgressReporter;
job->ClearExistingOutputs();
if( m_jobHandlers.count( job->GetType() ) )
{
result = m_jobHandlers[job->GetType()]( job );
}
m_reporter = existingReporter;

View File

@ -39,7 +39,7 @@ public:
JOB_DISPATCHER( KIWAY* aKiway );
void Register( const std::string& aJobTypeName, std::function<int( JOB* job )> aHandler,
std::function<bool( JOB* job, wxWindow* aParent )> aConfigHandler );
int RunJob( JOB* aJob, REPORTER* aReporter );
int RunJob( JOB* aJob, REPORTER* aReporter, PROGRESS_REPORTER* aProgressReporter );
bool HandleJobConfig( JOB* aJob, wxWindow* aParent );
void SetReporter( REPORTER* aReporter );
void SetProgressReporter( PROGRESS_REPORTER* aReporter );

View File

@ -709,11 +709,11 @@ bool KIWAY::ProcessEvent( wxEvent& aEvent )
}
int KIWAY::ProcessJob( KIWAY::FACE_T aFace, JOB* job, REPORTER* aReporter )
int KIWAY::ProcessJob( KIWAY::FACE_T aFace, JOB* job, REPORTER* aReporter, PROGRESS_REPORTER* aProgressReporter )
{
KIFACE* kiface = KiFACE( aFace );
return kiface->HandleJob( job, aReporter );
return kiface->HandleJob( job, aReporter, aProgressReporter );
}

View File

@ -447,8 +447,11 @@ void DIALOG_ERC::OnRunERCClick( wxCommandEvent& event )
testErc();
if( itemsNotAnnotated )
{
m_messages->ReportHead( wxString::Format( _( "%d symbol(s) require annotation.<br><br>" ),
itemsNotAnnotated ), RPT_SEVERITY_INFO );
itemsNotAnnotated ),
RPT_SEVERITY_INFO );
}
if( m_cancelled )
// @spellingerror

View File

@ -369,7 +369,7 @@ static struct IFACE : public KIFACE_BASE, public UNITS_PROVIDER
const wxString& aSrcFilePath, wxString& aErrors ) override;
int HandleJob( JOB* aJob, REPORTER* aReporter ) override;
int HandleJob( JOB* aJob, REPORTER* aReporter, PROGRESS_REPORTER* aProgressReporter ) override;
bool HandleJobConfig( JOB* aJob, wxWindow* aParent ) override;
@ -710,9 +710,9 @@ void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aProje
}
int IFACE::HandleJob( JOB* aJob, REPORTER* aReporter )
int IFACE::HandleJob( JOB* aJob, REPORTER* aReporter, PROGRESS_REPORTER* aProgressReporter )
{
return m_jobHandler->RunJob( aJob, aReporter );
return m_jobHandler->RunJob( aJob, aReporter, aProgressReporter );
}

View File

@ -50,6 +50,7 @@
#include <drawing_sheet/ds_data_model.h>
#include <paths.h>
#include <reporter.h>
#include <progress_reporter.h>
#include <string_utils.h>
#include <settings/settings_manager.h>
@ -228,8 +229,7 @@ void EESCHEMA_JOBS_HANDLER::InitRenderSettings( SCH_RENDER_SETTINGS* aRenderSett
if( !DS_DATA_MODEL::GetTheInstance().LoadDrawingSheet( absolutePath, &msg ) )
{
m_reporter->Report( wxString::Format( _( "Error loading drawing sheet '%s'." ),
path )
m_reporter->Report( wxString::Format( _( "Error loading drawing sheet '%s'." ), path )
+ wxS( "\n" ) + msg + wxS( "\n" ),
RPT_SEVERITY_ERROR );
return false;
@ -981,6 +981,9 @@ int EESCHEMA_JOBS_HANDLER::JobSymExportSvg( JOB* aJob )
return CLI::EXIT_CODES::ERR_UNKNOWN;
}
if( m_progressReporter )
m_progressReporter->KeepRefreshing();
LIB_SYMBOL* symbol = nullptr;
if( !svgJob->m_symbol.IsEmpty() )
@ -1021,6 +1024,12 @@ int EESCHEMA_JOBS_HANDLER::JobSymExportSvg( JOB* aJob )
for( const auto& [name, libSymbol] : libSymMap )
{
if( m_progressReporter )
{
m_progressReporter->AdvancePhase( wxString::Format( _( "Exporting %s" ), name ) );
m_progressReporter->KeepRefreshing();
}
exitCode = doSymExportSvg( svgJob, &renderSettings, libSymbol );
if( exitCode != CLI::EXIT_CODES::OK )
@ -1076,8 +1085,10 @@ int EESCHEMA_JOBS_HANDLER::JobSymUpgrade( JOB* aJob )
return CLI::EXIT_CODES::ERR_UNKNOWN;
}
bool shouldSave =
upgradeJob->m_force
if( m_progressReporter )
m_progressReporter->KeepRefreshing();
bool shouldSave = upgradeJob->m_force
|| schLibrary.GetFileFormatVersionAtLoad() < SEXPR_SYMBOL_LIB_FILE_VERSION;
if( shouldSave )
@ -1088,9 +1099,7 @@ int EESCHEMA_JOBS_HANDLER::JobSymUpgrade( JOB* aJob )
try
{
if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
{
schLibrary.SetFileName( upgradeJob->m_outputLibraryPath );
}
schLibrary.SetModified();
schLibrary.Save();
@ -1108,8 +1117,7 @@ int EESCHEMA_JOBS_HANDLER::JobSymUpgrade( JOB* aJob )
}
else
{
if( !SCH_IO_MGR::ConvertLibrary( nullptr, fn.GetAbsolutePath(),
upgradeJob->m_outputLibraryPath ) )
if( !SCH_IO_MGR::ConvertLibrary( nullptr, fn.GetAbsolutePath(), upgradeJob->m_outputLibraryPath ) )
{
m_reporter->Report( ( "Unable to convert library\n" ), RPT_SEVERITY_ERROR );
return CLI::EXIT_CODES::ERR_UNKNOWN;

View File

@ -134,6 +134,7 @@ class wxTopLevelWindow;
class TOOL_ACTION;
class JOB;
class REPORTER;
class PROGRESS_REPORTER;
/**
@ -242,7 +243,7 @@ struct KIFACE
*/
virtual void GetActions( std::vector<TOOL_ACTION*>& aActions ) const = 0;
virtual int HandleJob( JOB* aJob, REPORTER* aReporter )
virtual int HandleJob( JOB* aJob, REPORTER* aReporter, PROGRESS_REPORTER* aProgressReporter )
{
return 0;
}
@ -432,7 +433,8 @@ public:
bool ProcessEvent( wxEvent& aEvent ) override;
int ProcessJob( KIWAY::FACE_T aFace, JOB* aJob, REPORTER* aReporter = nullptr );
int ProcessJob( KIWAY::FACE_T aFace, JOB* aJob, REPORTER* aReporter = nullptr,
PROGRESS_REPORTER* aProgressReporter = nullptr );
bool ProcessJobConfigDialog( KIWAY::FACE_T aFace, JOB* aJob, wxWindow* aWindow );
/**

View File

@ -80,8 +80,7 @@ int CLI::JOBSET_RUN_COMMAND::doPerform( KIWAY& aKiway )
jobFile.LoadFromFile();
JOBS_RUNNER jobsRunner( &aKiway, &jobFile, project,
&CLI_REPORTER::GetInstance() );
JOBS_RUNNER jobsRunner( &aKiway, &jobFile, project, CLI_REPORTER::GetInstance(), nullptr );
int return_code = CLI::EXIT_CODES::SUCCESS;

View File

@ -53,8 +53,7 @@ std::map<JOBSET_DESTINATION_T, JOBSET_DESTINATION_T_INFO> JobsetDestinationTypeI
class DIALOG_JOBSET_RUN_LOG : public DIALOG_JOBSET_RUN_LOG_BASE
{
public:
DIALOG_JOBSET_RUN_LOG( wxWindow* aParent, JOBSET* aJobsFile,
JOBSET_DESTINATION* aDestination ) :
DIALOG_JOBSET_RUN_LOG( wxWindow* aParent, JOBSET* aJobsFile, JOBSET_DESTINATION* aDestination ) :
DIALOG_JOBSET_RUN_LOG_BASE( aParent ),
m_jobsFile( aJobsFile ),
m_destination( aDestination ),
@ -78,7 +77,8 @@ public:
m_jobList->SetImageList( imageList, wxIMAGE_LIST_SMALL );
int num = 1;
for( auto& job : aJobsFile->GetJobsForDestination( aDestination ) )
for( JOBSET_JOB& job : aJobsFile->GetJobsForDestination( aDestination ) )
{
int imageIdx = -1;
@ -260,17 +260,16 @@ public:
wxFileName fn = project.GetProjectFullName();
wxSetWorkingDirectory( fn.GetPath() );
JOBS_RUNNER jobRunner( &( m_frame->Kiway() ), m_jobsFile, &project );
auto* progressReporter = new WX_PROGRESS_REPORTER( m_frame, _( "Running jobs" ),
1 );
{
JOBS_PROGRESS_REPORTER progressReporter( m_frame, _( "Running Jobs" ) );
JOBS_RUNNER jobRunner( &m_frame->Kiway(), m_jobsFile, &project,
NULL_REPORTER::GetInstance(), &progressReporter );
if( JOBSET_DESTINATION* destination = GetDestination() )
jobRunner.RunJobsForDestination( destination );
UpdateStatus();
delete progressReporter;
}
// Bring the Kicad manager frame back to the front
m_frame->Raise();
@ -973,17 +972,16 @@ void PANEL_JOBSET::OnGenerateAllDestinationsClick( wxCommandEvent& event )
wxFileName fn = project.GetProjectFullName();
wxSetWorkingDirectory( fn.GetPath() );
JOBS_RUNNER jobRunner( &( m_frame->Kiway() ), m_jobsFile.get(), &project );
WX_PROGRESS_REPORTER* progressReporter =
new WX_PROGRESS_REPORTER( m_frame, _( "Running jobs" ), 1 );
{
JOBS_PROGRESS_REPORTER progressReporter( m_frame, _( "Running Jobs" ) );
JOBS_RUNNER jobRunner( &m_frame->Kiway(), m_jobsFile.get(), &project,
NULL_REPORTER::GetInstance(), &progressReporter );
jobRunner.RunJobsAllDestinations();
for( PANEL_DESTINATION* panel : GetDestinationPanels() )
panel->UpdateStatus();
delete progressReporter;
}
// Bring the Kicad manager frame back to the front
m_frame->Raise();

View File

@ -35,14 +35,13 @@
#include <gestfich.h>
JOBS_RUNNER::JOBS_RUNNER( KIWAY* aKiway, JOBSET* aJobsFile, PROJECT* aProject,
REPORTER* aReporter ) :
REPORTER& aReporter, JOBS_PROGRESS_REPORTER* aProgressReporter ) :
m_kiway( aKiway ),
m_jobsFile( aJobsFile ),
m_reporter( aReporter ),
m_progressReporter( aProgressReporter ),
m_project( aProject )
{
if( !m_reporter )
m_reporter = &NULL_REPORTER::GetInstance();
}
@ -138,8 +137,9 @@ int JOBS_RUNNER::runSpecialCopyFiles( const JOBSET_JOB* aJob, PROJECT* aProject
class JOBSET_OUTPUT_REPORTER : public WX_STRING_REPORTER
{
public:
JOBSET_OUTPUT_REPORTER( const wxString& aTempDirPath ) :
m_tempDirPath( aTempDirPath )
JOBSET_OUTPUT_REPORTER( const wxString& aTempDirPath, PROGRESS_REPORTER* aProgressReporter ) :
m_tempDirPath( aTempDirPath ),
m_progressReporter( aProgressReporter )
{
}
@ -153,12 +153,19 @@ public:
if( aSeverity == RPT_SEVERITY_ACTION )
text.Replace( m_tempDirPath, wxEmptyString );
if( m_progressReporter )
{
m_progressReporter->Report( text );
m_progressReporter->KeepRefreshing();
}
return WX_STRING_REPORTER::Report( text, aSeverity );
}
private:
wxString m_tempDirPath;
bool m_includeDebug;
PROGRESS_REPORTER* m_progressReporter;
};
@ -183,12 +190,9 @@ bool JOBS_RUNNER::RunJobsForDestination( JOBSET_DESTINATION* aDestination, bool
wxString tempDirPath = tmp.GetFullPath();
if( !wxFileName::Mkdir( tempDirPath, wxS_DIR_DEFAULT ) )
{
if( m_reporter )
{
msg = wxString::Format( wxT( "Failed to create temporary directory %s" ), tempDirPath );
m_reporter->Report( msg, RPT_SEVERITY_ERROR );
}
m_reporter.Report( msg, RPT_SEVERITY_ERROR );
aDestination->m_lastRunSuccess = false;
@ -199,22 +203,17 @@ bool JOBS_RUNNER::RunJobsForDestination( JOBSET_DESTINATION* aDestination, bool
if( !continueOuput )
{
if( m_reporter )
{
msg = wxString::Format( wxT( "Output precheck failed for output %s" ),
msg = wxString::Format( wxT( "Destination precheck failed for destination %s" ),
aDestination->m_id );
m_reporter->Report( msg, RPT_SEVERITY_ERROR );
}
m_reporter.Report( msg, RPT_SEVERITY_ERROR );
aDestination->m_lastRunSuccess = false;
return false;
}
if( m_reporter != nullptr )
{
msg += wxT( "|--------------------------------\n" );
msg += wxT( "| " );
msg += wxString::Format( wxT( "Performing jobs for output %s" ), aDestination->m_id );
msg += wxString::Format( wxT( "Running jobs for destination %s" ), aDestination->m_id );
msg += wxT( "\n" );
msg += wxT( "|--------------------------------\n" );
@ -232,41 +231,45 @@ bool JOBS_RUNNER::RunJobsForDestination( JOBSET_DESTINATION* aDestination, bool
msg += wxT( "\n" );
msg += wxT( "\n" );
m_reporter->Report( msg, RPT_SEVERITY_INFO );
}
m_reporter.Report( msg, RPT_SEVERITY_INFO );
std::vector<JOB_OUTPUT> outputs;
int jobNum = 1;
jobNum = 1;
int failCount = 0;
int successCount = 0;
wxSetEnv( OUTPUT_WORK_PATH_VAR_NAME, tempDirPath );
for( const JOBSET_JOB& job : jobsForDestination )
{
if( m_reporter != nullptr )
{
msg = wxT( "|--------------------------------\n" );
msg += wxString::Format( wxT( "| Running job %d, %s" ), jobNum, job.GetDescription() );
jobNum++;
msg += wxString::Format( wxT( "| Running job %d: %s" ), jobNum, job.GetDescription() );
msg += wxT( "\n" );
msg += wxT( "|--------------------------------\n" );
m_reporter->Report( msg, RPT_SEVERITY_INFO );
m_reporter.Report( msg, RPT_SEVERITY_INFO );
if( m_progressReporter )
{
msg.Printf( _( "Running job %d: %s" ), jobNum, job.GetDescription() );
m_progressReporter->AdvanceJob( msg );
m_progressReporter->KeepRefreshing();
}
jobNum++;
KIWAY::FACE_T iface = JOB_REGISTRY::GetKifaceType( job.m_type );
job.m_job->SetTempOutputDirectory( tempDirPath );
REPORTER* reporterToUse = m_reporter;
REPORTER* reporterToUse = &m_reporter;
if( !reporterToUse || reporterToUse == &NULL_REPORTER::GetInstance() )
if( reporterToUse == &NULL_REPORTER::GetInstance() )
{
reporterToUse = new JOBSET_OUTPUT_REPORTER( tempDirPath );
reporterToUse = new JOBSET_OUTPUT_REPORTER( tempDirPath, m_progressReporter );
aDestination->m_lastRunReporters[job.m_id] = reporterToUse;
}
@ -275,7 +278,7 @@ bool JOBS_RUNNER::RunJobsForDestination( JOBSET_DESTINATION* aDestination, bool
if( iface < KIWAY::KIWAY_FACE_COUNT )
{
result = m_kiway->ProcessJob( iface, job.m_job.get(), reporterToUse );
result = m_kiway->ProcessJob( iface, job.m_job.get(), reporterToUse, m_progressReporter );
}
else
{
@ -292,8 +295,6 @@ bool JOBS_RUNNER::RunJobsForDestination( JOBSET_DESTINATION* aDestination, bool
aDestination->m_lastRunSuccessMap[job.m_id] = ( result == CLI::EXIT_CODES::SUCCESS );
if( m_reporter )
{
if( result == CLI::EXIT_CODES::SUCCESS )
{
wxString msg_fmt = wxT( "\033[32;1m%s\033[0m\n" );
@ -310,8 +311,7 @@ bool JOBS_RUNNER::RunJobsForDestination( JOBSET_DESTINATION* aDestination, bool
}
msg += wxT( "\n\n" );
m_reporter->Report( msg, RPT_SEVERITY_INFO );
}
m_reporter.Report( msg, RPT_SEVERITY_INFO );
if( result == CLI::EXIT_CODES::ERR_RC_VIOLATIONS )
{
@ -337,16 +337,13 @@ bool JOBS_RUNNER::RunJobsForDestination( JOBSET_DESTINATION* aDestination, bool
aDestination->m_lastRunSuccess = success;
if( m_reporter )
{
msg = wxString::Format( wxT( "\n\n\033[33;1m%d %s, %d %s\033[0m\n" ),
successCount,
wxT( "jobs succeeded" ),
failCount,
wxT( "job failed" ) );
m_reporter->Report( msg, RPT_SEVERITY_INFO );
}
m_reporter.Report( msg, RPT_SEVERITY_INFO );
return success;
}

View File

@ -20,18 +20,48 @@
#pragma once
#include <widgets/wx_progress_reporters.h>
class JOBSET;
struct JOBSET_DESTINATION;
struct JOBSET_JOB;
class KIWAY;
class REPORTER;
class PROGRESS_REPORTER;
class PROJECT;
class JOBS_PROGRESS_REPORTER : public WX_PROGRESS_REPORTER
{
public:
JOBS_PROGRESS_REPORTER(wxWindow* aParent, const wxString& aTitle ) :
WX_PROGRESS_REPORTER( aParent, aTitle, 1000, false )
{}
void AdvancePhase() override
{
}
void AdvanceJob( const wxString& aMessage )
{
m_jobStatus = aMessage;
WX_PROGRESS_REPORTER::Report( aMessage );
}
void Report( const wxString& aMessage ) override
{
WX_PROGRESS_REPORTER::Report( m_jobStatus + wxS( "\n" ) + aMessage );
}
private:
wxString m_jobStatus;
};
class JOBS_RUNNER
{
public:
JOBS_RUNNER( KIWAY* aKiway, JOBSET* aJobsFile, PROJECT* aProject,
REPORTER* aReporter = nullptr );
REPORTER& aReporter, JOBS_PROGRESS_REPORTER* aProgressReporter );
bool RunJobsAllDestinations( bool aBail = false );
bool RunJobsForDestination( JOBSET_DESTINATION* aDestination, bool aBail = false );
@ -43,6 +73,7 @@ private:
private:
KIWAY* m_kiway;
JOBSET* m_jobsFile;
REPORTER* m_reporter;
REPORTER& m_reporter;
JOBS_PROGRESS_REPORTER* m_progressReporter;
PROJECT* m_project;
};

View File

@ -353,7 +353,7 @@ static struct IFACE : public KIFACE_BASE, public UNITS_PROVIDER
const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
const wxString& aSrcFilePath, wxString& aErrors ) override;
int HandleJob( JOB* aJob, REPORTER* aReporter ) override;
int HandleJob( JOB* aJob, REPORTER* aReporter, PROGRESS_REPORTER* aProgressReporter ) override;
bool HandleJobConfig( JOB* aJob, wxWindow* aParent ) override;
@ -585,9 +585,9 @@ void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aSrcPr
}
int IFACE::HandleJob( JOB* aJob, REPORTER* aReporter )
int IFACE::HandleJob( JOB* aJob, REPORTER* aReporter, PROGRESS_REPORTER* aProgressReporter )
{
return m_jobHandler->RunJob( aJob, aReporter );
return m_jobHandler->RunJob( aJob, aReporter, aProgressReporter );
}

View File

@ -76,6 +76,7 @@
#include <project_pcb.h>
#include <pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h>
#include <reporter.h>
#include <progress_reporter.h>
#include <wildcards_and_files_ext.h>
#include <export_vrml.h>
#include <wx/wfstream.h>
@ -1139,6 +1140,12 @@ int PCBNEW_JOBS_HANDLER::JobExportGerbers( JOB* aJob )
BuildPlotFileName( &fn, outPath, layerName, fileExt );
wxString fullname = fn.GetFullName();
if( m_progressReporter )
{
m_progressReporter->AdvancePhase( wxString::Format( _( "Exporting %s" ), fullname ) );
m_progressReporter->KeepRefreshing();
}
jobfile_writer.AddGbrFile( layer, fullname );
if( aJob->GetVarOverrides().contains( wxT( "LAYER" ) ) )
@ -1168,8 +1175,7 @@ int PCBNEW_JOBS_HANDLER::JobExportGerbers( JOB* aJob )
}
else
{
m_reporter->Report( wxString::Format( _( "Failed to plot to '%s'.\n" ),
fn.GetFullPath() ),
m_reporter->Report( wxString::Format( _( "Failed to plot to '%s'.\n" ), fn.GetFullPath() ),
RPT_SEVERITY_ERROR );
exitCode = CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT;
}
@ -1727,16 +1733,16 @@ int PCBNEW_JOBS_HANDLER::JobExportFpUpgrade( JOB* aJob )
return CLI::EXIT_CODES::ERR_UNKNOWN;
}
if( m_progressReporter )
m_progressReporter->KeepRefreshing();
bool shouldSave = upgradeJob->m_force;
for( const auto& footprint : fpLib.GetFootprints() )
{
if( footprint.second->GetFootprint()->GetFileFormatVersionAtLoad()
< SEXPR_BOARD_FILE_VERSION )
{
if( footprint.second->GetFootprint()->GetFileFormatVersionAtLoad() < SEXPR_BOARD_FILE_VERSION )
shouldSave = true;
}
}
if( shouldSave )
{
@ -1810,6 +1816,12 @@ int PCBNEW_JOBS_HANDLER::JobExportFpSvg( JOB* aJob )
for( const auto& [fpName, fpCacheEntry] : fpLib.GetFootprints() )
{
if( m_progressReporter )
{
m_progressReporter->AdvancePhase( wxString::Format( _( "Exporting %s" ), fpName ) );
m_progressReporter->KeepRefreshing();
}
if( !svgJob->m_footprint.IsEmpty() )
{
// skip until we find the right footprint
@ -2019,7 +2031,7 @@ int PCBNEW_JOBS_HANDLER::JobExportDrc( JOB* aJob )
drcEngine->SetSchematicNetlist( netlist.get() );
}
drcEngine->SetProgressReporter( nullptr );
drcEngine->SetProgressReporter( m_progressReporter );
drcEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )