KiCad PCB EDA Suite
Loading...
Searching...
No Matches
jobs_runner.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2024 Mark Roszko <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <common.h>
22#include <cli/exit_codes.h>
23#include <jobs_runner.h>
24#include <jobs/job_registry.h>
25#include <jobs/jobset.h>
28#include <kiway.h>
29#include <kiway_express.h>
30#include <reporter.h>
31#include <wx/process.h>
32#include <wx/txtstrm.h>
33#include <wx/sstream.h>
34#include <wx/wfstream.h>
35#include <gestfich.h>
36
37JOBS_RUNNER::JOBS_RUNNER( KIWAY* aKiway, JOBSET* aJobsFile, PROJECT* aProject,
38 REPORTER* aReporter ) :
39 m_kiway( aKiway ),
40 m_jobsFile( aJobsFile ),
41 m_reporter( aReporter ),
42 m_project( aProject )
43{
44 if( !m_reporter )
45 {
47 }
48}
49
50
52{
53 bool success = true;
54
55 for( JOBSET_OUTPUT& output : m_jobsFile->GetOutputs() )
56 {
57 success &= RunJobsForOutput( &output, aBail );
58 }
59
60 return success;
61}
62
63
65{
66 JOB_SPECIAL_EXECUTE* specialJob = static_cast<JOB_SPECIAL_EXECUTE*>( aJob->m_job.get() );
67
68 wxString cmd = ExpandEnvVarSubstitutions( specialJob->m_command, m_project );
69
70 // static cast required because wx uses `long` which is 64-bit on Linux but 32-bit on Windows
71 wxProcess process;
72 process.Redirect();
73
74 int result = static_cast<int>( wxExecute( cmd, wxEXEC_SYNC, &process ) );
75
76 if( specialJob->m_recordOutput )
77 {
78 if( specialJob->GetConfiguredOutputPath().IsEmpty() )
79 {
80 wxFileName fn( aJob->m_id );
81 fn.SetExt( wxT( "log" ) );
82 specialJob->SetConfiguredOutputPath( fn.GetFullPath() );
83 }
84
85 wxFFileOutputStream procOutput( specialJob->GetFullOutputPath( aProject ) );
86
87 if( !procOutput.IsOk() )
89
90 wxInputStream* inputStream = process.GetInputStream();
91 if( inputStream )
92 {
93 inputStream->Read( procOutput );
94 }
95 procOutput.Close();
96 }
97
98 if( specialJob->m_ignoreExitcode )
99 {
100 return CLI::EXIT_CODES::OK;
101 }
102
103 return result;
104}
105
106
108{
109 JOB_SPECIAL_COPYFILES* job = static_cast<JOB_SPECIAL_COPYFILES*>( aJob->m_job.get() );
110
111 wxString source = ExpandTextVars( job->m_source, aProject );
112
113 if( source.IsEmpty() )
115
116 wxString projectPath = aProject->GetProjectPath();
117 wxFileName sourceFn( source );
118 sourceFn.MakeAbsolute( projectPath );
119
120 wxFileName destFn( job->GetFullOutputPath( aProject ) );
121
122 if( !job->m_dest.IsEmpty() )
123 destFn.AppendDir( job->m_dest );
124
125 std::vector<wxString> exclusions;
126
127 for( const JOBSET_OUTPUT& output : m_jobsFile->GetOutputs() )
128 exclusions.push_back( projectPath + output.m_outputHandler->GetOutputPath() );
129
130 wxString errors;
131 int copyCount = 0;
132 bool success = CopyFilesOrDirectory( sourceFn.GetFullPath(), destFn.GetFullPath(),
133 errors, copyCount, exclusions );
134
135 if( !success )
137
138 if( job->m_generateErrorOnNoCopy && copyCount == 0 )
140
141 return CLI::EXIT_CODES::OK;
142}
143
144
146{
147public:
148 JOBSET_OUTPUT_REPORTER( const wxString& aTempDirPath ) :
149 m_tempDirPath( aTempDirPath )
150 {
151 }
152
153 REPORTER& Report( const wxString& aText, SEVERITY aSeverity ) override
154 {
155 wxString text( aText );
156
157 if( aSeverity == RPT_SEVERITY_ACTION )
158 text.Replace( m_tempDirPath, wxEmptyString );
159
160 return WX_STRING_REPORTER::Report( text, aSeverity );
161 }
162
163private:
165};
166
167
169{
170 bool genOutputs = true;
171 bool success = true;
172 std::vector<JOBSET_JOB> jobsForOutput = m_jobsFile->GetJobsForOutput( aOutput );
173 wxString msg;
174
175 wxFileName tmp;
176 tmp.AssignDir( wxFileName::GetTempDir() );
177 tmp.AppendDir( KIID().AsString() );
178
179 aOutput->m_lastRunSuccessMap.clear();
180
181 for( auto& [name, reporter] : aOutput->m_lastRunReporters )
182 delete reporter;
183
184 aOutput->m_lastRunReporters.clear();
185
186 wxString tempDirPath = tmp.GetFullPath();
187
188 if( !wxFileName::Mkdir( tempDirPath, wxS_DIR_DEFAULT ) )
189 {
190 if( m_reporter )
191 {
192 msg = wxString::Format( wxT( "Failed to create temporary directory %s" ), tempDirPath );
194 }
195
196 aOutput->m_lastRunSuccess = false;
197
198 return false;
199 }
200
201 bool continueOuput = aOutput->m_outputHandler->OutputPrecheck();
202
203 if( !continueOuput )
204 {
205 if( m_reporter )
206 {
207 msg = wxString::Format( wxT( "Output precheck failed for output %s" ), aOutput->m_id );
209 }
210
211 aOutput->m_lastRunSuccess = false;
212 return false;
213 }
214
215 if( m_reporter != nullptr )
216 {
217 msg += wxT( "|--------------------------------\n" );
218 msg += wxT( "| " );
219 msg += wxString::Format( "Performing jobs for output %s", aOutput->m_id );
220 msg += wxT( "\n" );
221 msg += wxT( "|--------------------------------\n" );
222
223 msg += wxString::Format( wxT( "|%-5s | %-50s\n" ), wxT( "No." ), wxT( "Description" ) );
224
225 int jobNum = 1;
226
227 for( const JOBSET_JOB& job : jobsForOutput )
228 {
229 msg += wxString::Format( wxT( "|%-5d | %-50s\n" ), jobNum, job.GetDescription() );
230 jobNum++;
231 }
232
233 msg += wxT( "|--------------------------------\n" );
234 msg += wxT( "\n" );
235 msg += wxT( "\n" );
236
238 }
239
240 std::vector<JOB_OUTPUT> outputs;
241
242 int jobNum = 1;
243 int failCount = 0;
244 int successCount = 0;
245
246 for( const JOBSET_JOB& job : jobsForOutput )
247 {
248 if( m_reporter != nullptr )
249 {
250 msg = wxT( "|--------------------------------\n" );
251 msg += wxString::Format( wxT( "| Running job %d, %s" ), jobNum, job.GetDescription() );
252 msg += wxT( "\n" );
253 msg += wxT( "|--------------------------------\n" );
254
256 }
257
258 KIWAY::FACE_T iface = JOB_REGISTRY::GetKifaceType( job.m_type );
259
260 job.m_job->SetTempOutputDirectory( tempDirPath );
261
262 REPORTER* reporterToUse = m_reporter;
263
264 if( !reporterToUse || reporterToUse == &NULL_REPORTER::GetInstance() )
265 {
266 reporterToUse = new JOBSET_OUTPUT_REPORTER( tempDirPath );
267 aOutput->m_lastRunReporters[job.m_id] = reporterToUse;
268 }
269
270 int result = CLI::EXIT_CODES::SUCCESS;
271
272 if( iface < KIWAY::KIWAY_FACE_COUNT )
273 {
274 result = m_kiway->ProcessJob( iface, job.m_job.get(), reporterToUse );
275 }
276 else
277 {
278 // special jobs
279 if( job.m_job->GetType() == "special_execute" )
280 {
281 result = runSpecialExecute( &job, m_project );
282 }
283 else if( job.m_job->GetType() == "special_copyfiles" )
284 {
285 result = runSpecialCopyFiles( &job, m_project );
286 }
287 }
288
289 aOutput->m_lastRunSuccessMap[job.m_id] = ( result == CLI::EXIT_CODES::SUCCESS );
290
291 if( m_reporter )
292 {
293 if( result == CLI::EXIT_CODES::SUCCESS )
294 {
295 wxString msg_fmt = wxT( "\033[32;1m%s\033[0m\n" );
296 msg = wxString::Format( msg_fmt, _( "Job successful" ) );
297
298 successCount++;
299 }
300 else
301 {
302 wxString msg_fmt = wxT( "\033[31;1m%s\033[0m\n" );
303 msg = wxString::Format( msg_fmt, _( "Job failed" ) );
304
305 failCount++;
306 }
307
308 msg += wxT( "\n\n" );
310 }
311
313 {
314 success = false;
315
316 if( aBail )
317 break;
318 }
319 else if( result != CLI::EXIT_CODES::SUCCESS )
320 {
321 genOutputs = false;
322 success = false;
323
324 if( aBail )
325 break;
326 }
327 }
328
329 if( genOutputs )
330 success &= aOutput->m_outputHandler->HandleOutputs( tempDirPath, m_project, outputs );
331
332 aOutput->m_lastRunSuccess = success;
333
334 if( m_reporter )
335 {
336 msg = wxString::Format( wxT( "\n\n\033[33;1m%d %s, %d %s\033[0m\n" ),
337 successCount,
338 wxT( "jobs succeeded" ),
339 failCount,
340 wxT( "job failed" ) );
341
343 }
344
345 return success;
346}
const char * name
Definition: DXF_plotter.cpp:59
REPORTER & Report(const wxString &aText, SEVERITY aSeverity) override
Report a string with a given severity.
JOBSET_OUTPUT_REPORTER(const wxString &aTempDirPath)
Definition: jobset.h:105
std::vector< JOBSET_JOB > GetJobsForOutput(JOBSET_OUTPUT *aOutput)
Definition: jobset.cpp:302
std::vector< JOBSET_OUTPUT > & GetOutputs()
Definition: jobset.h:118
virtual bool OutputPrecheck()
Checks if the output process can proceed before doing anything else This can include user prompts.
Definition: jobs_output.h:44
virtual bool HandleOutputs(const wxString &aBaseTempPath, PROJECT *aProject, const std::vector< JOB_OUTPUT > &aOutputsToHandle)=0
bool RunJobsForOutput(JOBSET_OUTPUT *aOutput, bool aBail=false)
KIWAY * m_kiway
Definition: jobs_runner.h:44
JOBSET * m_jobsFile
Definition: jobs_runner.h:45
bool RunJobsAllOutputs(bool aBail=false)
Definition: jobs_runner.cpp:51
JOBS_RUNNER(KIWAY *aKiway, JOBSET *aJobsFile, PROJECT *aProject, REPORTER *aReporter=nullptr)
Definition: jobs_runner.cpp:37
int runSpecialExecute(const JOBSET_JOB *aJob, PROJECT *aProject)
Definition: jobs_runner.cpp:64
PROJECT * m_project
Definition: jobs_runner.h:47
REPORTER * m_reporter
Definition: jobs_runner.h:46
int runSpecialCopyFiles(const JOBSET_JOB *aJob, PROJECT *aProject)
static KIWAY::FACE_T GetKifaceType(const wxString &aName)
void SetConfiguredOutputPath(const wxString &aPath)
Sets the configured output path for the job, this path is always saved to file.
Definition: job.cpp:153
wxString GetFullOutputPath(PROJECT *aProject) const
Returns the full output path for the job, taking into account the configured output path,...
Definition: job.cpp:100
wxString GetConfiguredOutputPath() const
Returns the configured output path for the job.
Definition: job.h:226
Definition: kiid.h:49
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition: kiway.h:285
FACE_T
Known KIFACE implementations.
Definition: kiway.h:291
@ KIWAY_FACE_COUNT
Definition: kiway.h:301
int ProcessJob(KIWAY::FACE_T aFace, JOB *aJob, REPORTER *aReporter=nullptr)
Definition: kiway.cpp:711
static REPORTER & GetInstance()
Definition: reporter.cpp:115
Container for project specific data.
Definition: project.h:64
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:146
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:72
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
A wrapper for reporting to a wxString object.
Definition: reporter.h:171
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
Definition: reporter.cpp:76
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:351
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
Definition: common.cpp:59
The common library.
#define _(s)
bool CopyFilesOrDirectory(const wxString &aSourcePath, const wxString &aDestDir, wxString &aErrors, int &fileCopiedCount, const std::vector< wxString > &aExclusions)
Definition: gestfich.cpp:411
static const int ERR_ARGS
Definition: exit_codes.h:31
static const int OK
Definition: exit_codes.h:30
static const int ERR_RC_VIOLATIONS
Rules check violation count was greater than 0.
Definition: exit_codes.h:37
static const int SUCCESS
Definition: exit_codes.h:29
static const int ERR_INVALID_OUTPUT_CONFLICT
Definition: exit_codes.h:34
static const int ERR_UNKNOWN
Definition: exit_codes.h:32
static PGM_BASE * process
Definition: pgm_base.cpp:1070
SEVERITY
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_INFO
@ RPT_SEVERITY_ACTION
wxString m_id
Definition: jobset.h:46
std::shared_ptr< JOB > m_job
Definition: jobset.h:49
wxString m_id
Definition: jobset.h:85
JOBS_OUTPUT_HANDLER * m_outputHandler
Definition: jobset.h:88
std::unordered_map< wxString, std::optional< bool > > m_lastRunSuccessMap
Definition: jobset.h:96
std::optional< bool > m_lastRunSuccess
Definition: jobset.h:95
std::unordered_map< wxString, REPORTER * > m_lastRunReporters
Definition: jobset.h:97