KiCad PCB EDA Suite
Loading...
Searching...
No Matches
kicad_cli.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) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25
26#include <wx/filename.h>
27#include <wx/log.h>
28#include <wx/stdpaths.h>
29#include <wx/wxcrtvararg.h> //for wxPrintf
30
31#include <kiway.h>
32#include <macros.h>
33#include <paths.h>
36#include <systemdirsappend.h>
37#include <trace_helpers.h>
38
39#include <stdexcept>
40
41#include "pgm_kicad.h"
42#include "kicad_manager_frame.h"
43
44#include <build_version.h>
45#include <kiplatform/app.h>
47#include <locale_io.h>
48
49#include "cli/command_pcb.h"
63#include "cli/command_fp.h"
67#include "cli/command_sch.h"
69#include "cli/command_sym.h"
73#include "cli/command_version.h"
74#include "cli/exit_codes.h"
75#include "cli/cli_names.h"
76
77// Add this header after all others, to avoid a collision name in a Windows header
78// on mingw.
79#include <wx/app.h>
80
81// a dummy to quiet linking with EDA_BASE_FRAME::config();
82#include <kiface_base.h>
84{
85 // This function should never be called. It is only referenced from
86 // EDA_BASE_FRAME::config() and this is only provided to satisfy the linker,
87 // not to be actually called.
88 wxLogFatalError( wxT( "Unexpected call to Kiface() in kicad/kicad.cpp" ) );
89
90 throw std::logic_error( "Unexpected call to Kiface() in kicad/kicad.cpp" );
91}
92
93
95
96
98{
99 return program;
100}
101
102
103// Similar to PGM_BASE& Pgm(), but return nullptr when a *.ki_face is run from a python script.
105{
106 return &program;
107}
108
109
111{
112 return program;
113}
114
115
117{
119
120 std::vector<COMMAND_ENTRY> subCommands;
121
122 COMMAND_ENTRY( CLI::COMMAND* aHandler ) : handler( aHandler ){};
123 COMMAND_ENTRY( CLI::COMMAND* aHandler, std::vector<COMMAND_ENTRY> aSub ) :
124 handler( aHandler ), subCommands( aSub ){};
125};
126
127
157
158
159static std::vector<COMMAND_ENTRY> commandStack = {
160 {
161 &fpCmd,
162 {
163 {
165 {
167 }
168 },
169 {
171 }
172 }
173 },
174 {
175 &pcbCmd,
176 {
177 {
179 {
188 }
189 }
190 }
191 },
192 {
193 &schCmd,
194 {
195 {
197 {
206 }
207 }
208 }
209 },
210 {
211 &symCmd,
212 {
213 {
215 {
217 }
218 },
219 {
221 }
222 }
223 },
224 {
225 &versionCmd,
226 }
227};
228
229
230static void recurseArgParserBuild( argparse::ArgumentParser& aArgParser, COMMAND_ENTRY& aEntry )
231{
232 aArgParser.add_subparser( aEntry.handler->GetArgParser() );
233
234 for( COMMAND_ENTRY& subEntry : aEntry.subCommands )
235 {
236 recurseArgParserBuild( aEntry.handler->GetArgParser(), subEntry );
237 }
238}
239
240
241static COMMAND_ENTRY* recurseArgParserSubCommandUsed( argparse::ArgumentParser& aArgParser,
242 COMMAND_ENTRY& aEntry )
243{
244 COMMAND_ENTRY* cliCmd = nullptr;
245
246 if( aArgParser.is_subcommand_used( aEntry.handler->GetName() ) )
247 {
248 for( COMMAND_ENTRY& subentry : aEntry.subCommands )
249 {
250 cliCmd = recurseArgParserSubCommandUsed( aEntry.handler->GetArgParser(), subentry );
251 if( cliCmd )
252 break;
253 }
254
255 if(!cliCmd)
256 cliCmd = &aEntry;
257 }
258
259 return cliCmd;
260}
261
262
263static void printHelp( argparse::ArgumentParser& argParser )
264{
265 std::stringstream ss;
266 ss << argParser;
267 wxPrintf( FROM_UTF8( ss.str().c_str() ) );
268}
269
270
272{
274 App().SetAppDisplayName( wxT( "KiCad-cli" ) );
275 // App name can be used by internal code to know if this is a
276 // kicad CLI app or a GUI app that is running
277 App().SetClassName( KICAD_CLI_APP_NAME );
278
279#if defined( DEBUG )
280 wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();
281
282 if( !wxIsAbsolutePath( absoluteArgv0 ) )
283 {
284 wxLogError( wxT( "No meaningful argv[0]" ) );
285 return false;
286 }
287#endif
288
289 if( !InitPgm( true, true) )
290 return false;
291
295 m_bm.Init();
296
297 return true;
298}
299
300
302{
303 argparse::ArgumentParser argParser( std::string( "kicad-cli" ), GetMajorMinorVersion().ToStdString(),
304 argparse::default_arguments::none );
305
306 argParser.add_argument( "-v", ARG_VERSION )
307 .default_value( false )
308 .help( UTF8STDSTR( _( "prints version information and exits" ) ) )
309 .implicit_value( true )
310 .nargs( 0 );
311
312 argParser.add_argument( ARG_HELP_SHORT, ARG_HELP )
313 .default_value( false )
314 .help( UTF8STDSTR( ARG_HELP_DESC ) )
315 .implicit_value( true )
316 .nargs( 0 );
317
318 for( COMMAND_ENTRY& entry : commandStack )
319 {
320 recurseArgParserBuild( argParser, entry );
321 }
322
323 try
324 {
325 // Use the C locale to parse arguments
326 // Otherwise the decimal separator for the locale will be applied
328 argParser.parse_args( m_argcUtf8, m_argvUtf8 );
329 }
330 // std::runtime_error doesn't seem to be enough for the scan<>()
331 catch( const std::exception& err )
332 {
333 wxPrintf( "%s\n", err.what() );
334
335 // find the correct argparser object to output the command usage info
336 COMMAND_ENTRY* cliCmd = nullptr;
337 for( COMMAND_ENTRY& entry : commandStack )
338 {
339 if( argParser.is_subcommand_used( entry.handler->GetName() ) )
340 {
341 cliCmd = recurseArgParserSubCommandUsed( argParser, entry );
342 }
343 }
344
345 // arg parser uses a stream overload for printing the help
346 // we want to intercept so we can wxString the utf8 contents
347 // because on windows our terminal codepage might not be utf8
348 if( cliCmd )
349 cliCmd->handler->PrintHelp();
350 else
351 {
352 printHelp( argParser );
353 }
354
356 }
357
358 if( argParser[ ARG_HELP ] == true )
359 {
360 std::stringstream ss;
361 ss << argParser;
362 wxPrintf( FROM_UTF8( ss.str().c_str() ) );
363
364 return 0;
365 }
366
367 CLI::COMMAND* cliCmd = nullptr;
368
369 // the version arg gets redirected to the version subcommand
370 if( argParser[ARG_VERSION] == true )
371 {
372 cliCmd = &versionCmd;
373 }
374
375 if( !cliCmd )
376 {
377 for( COMMAND_ENTRY& entry : commandStack )
378 {
379 if( argParser.is_subcommand_used( entry.handler->GetName() ) )
380 {
381 COMMAND_ENTRY* cmdSubEntry = recurseArgParserSubCommandUsed( argParser, entry );
382 if( cmdSubEntry != nullptr )
383 {
384 cliCmd = cmdSubEntry->handler;
385 break;
386 }
387 }
388 }
389 }
390
391 if( cliCmd )
392 {
393 int exitCode = cliCmd->Perform( Kiway );
394
395 if( exitCode != CLI::EXIT_CODES::AVOID_CLOSING )
396 {
397 return exitCode;
398 }
399 else
400 {
401 return 0;
402 }
403 }
404 else
405 {
406 printHelp( argParser );
407
409 }
410}
411
412
414{
416
418 {
420 m_settings_manager->Save();
421 }
422
423 // Destroy everything in PGM_KICAD,
424 // especially wxSingleInstanceCheckerImpl earlier than wxApp and earlier
425 // than static destruction would.
426 Destroy();
427}
428
429
430void PGM_KICAD::MacOpenFile( const wxString& aFileName )
431{
432#if defined( __WXMAC__ )
433 wxFAIL_MSG( "kicad-cli should not call MacOpenFile" );
434#endif
435}
436
437
439{
440 // unlike a normal destructor, this is designed to be called more
441 // than once safely:
442
443 m_bm.End();
444
446}
447
448
450
451
455struct APP_KICAD_CLI : public wxAppConsole
456{
457 APP_KICAD_CLI() : wxAppConsole()
458 {
459 // Init the environment each platform wants
461 }
462
463
464 bool OnInit() override
465 {
466 // Perform platform-specific init tasks
467 if( !KIPLATFORM::APP::Init() )
468 return false;
469
470 if( !program.OnPgmInit() )
471 {
473 return false;
474 }
475
476 return true;
477 }
478
479 int OnExit() override
480 {
482
483#if defined( __FreeBSD__ )
484 // Avoid wxLog crashing when used in destructors.
485 wxLog::EnableLogging( false );
486#endif
487
488 return wxAppConsole::OnExit();
489 }
490
491 int OnRun() override
492 {
493 try
494 {
495 return program.OnPgmRun();
496 }
497 catch( ... )
498 {
499 Pgm().HandleException( std::current_exception() );
500 }
501
502 return -1;
503 }
504
505 int FilterEvent( wxEvent& aEvent ) override
506 {
507 return Event_Skip;
508 }
509
510#if defined( DEBUG )
514 bool ProcessEvent( wxEvent& aEvent ) override
515 {
516 if( aEvent.GetEventType() == wxEVT_CHAR || aEvent.GetEventType() == wxEVT_CHAR_HOOK )
517 {
518 wxKeyEvent* keyEvent = static_cast<wxKeyEvent*>( &aEvent );
519
520 if( keyEvent )
521 {
522 wxLogTrace( kicadTraceKeyEvent, "APP_KICAD::ProcessEvent %s", dump( *keyEvent ) );
523 }
524 }
525
526 aEvent.Skip();
527 return false;
528 }
529
537 bool OnExceptionInMainLoop() override
538 {
539 try
540 {
541 throw;
542 }
543 catch( ... )
544 {
545 Pgm().HandleException( std::current_exception() );
546 }
547
548 return false; // continue on. Return false to abort program
549 }
550#endif
551};
552
553IMPLEMENT_APP_CONSOLE( APP_KICAD_CLI )
554
555
556// The C++ project manager supports one open PROJECT, so Prj() calls within
557// this link image need this function.
559{
560 return Kiway.Prj();
561}
wxString GetMajorMinorVersion()
Get only the major and minor version in a string major.minor.
argparse::ArgumentParser & GetArgParser()
Definition: command.h:54
const std::string & GetName() const
Definition: command.h:55
void PrintHelp()
Definition: command.cpp:41
int Perform(KIWAY &aKiway)
Entry point to processing commands from args and doing work.
Definition: command.cpp:49
A KIFACE implementation.
Definition: kiface_base.h:39
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition: kiway.h:279
void OnKiwayEnd()
Definition: kiway.cpp:748
virtual PROJECT & Prj() const
Return the PROJECT associated with this KIWAY.
Definition: kiway.cpp:196
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:41
Container for data for KiCad programs.
Definition: pgm_base.h:96
virtual wxApp & App()
Returns a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe.
Definition: pgm_base.cpp:167
int m_argcUtf8
argv parameters converted to utf8 form, because wxwidgets has opinions and will return argv as either...
Definition: pgm_base.h:395
std::unique_ptr< SETTINGS_MANAGER > m_settings_manager
Definition: pgm_base.h:371
void Destroy()
Definition: pgm_base.cpp:153
bool InitPgm(bool aHeadless=false, bool aSkipPyInit=false, bool aIsUnitTest=false)
Initialize this program.
Definition: pgm_base.cpp:402
char ** m_argvUtf8
Definition: pgm_base.h:392
void BuildArgvUtf8()
Builds the UTF8 based argv variable.
Definition: pgm_base.cpp:387
void HandleException(std::exception_ptr aPtr)
A excepion handler to be used at the top level if exceptions bubble up that for.
Definition: pgm_base.cpp:886
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:136
void SaveCommonSettings()
Save the program (process) settings subset which are stored .kicad_common.
Definition: pgm_base.cpp:612
PGM_KICAD extends PGM_BASE to bring in FileHistory() and PdfBrowser() which were moved from EDA_APP i...
Definition: pgm_kicad.h:38
bool OnPgmInit()
Definition: kicad.cpp:94
void Destroy()
Definition: kicad.cpp:396
void MacOpenFile(const wxString &aFileName) override
Specific to MacOSX (not used under Linux or Windows).
Definition: kicad.cpp:383
void OnPgmExit()
Definition: kicad.cpp:366
APP_SETTINGS_BASE * PgmSettings()
Definition: pgm_kicad.h:55
int OnPgmRun()
Definition: kicad.cpp:360
BIN_MOD m_bm
Definition: pgm_kicad.h:68
Container for project specific data.
Definition: project.h:64
T * RegisterSettings(T *aSettings, bool aLoadNow=true)
Takes ownership of the pointer passed in.
void SetKiway(KIWAY *aKiway)
Associate this setting manager with the given Kiway.
#define KICAD_CLI_APP_NAME
Definition: cli_names.h:23
#define ARG_HELP
Definition: command.h:30
#define UTF8STDSTR(s)
Definition: command.h:27
#define ARG_HELP_DESC
Definition: command.h:32
#define ARG_VERSION
Definition: command.h:29
#define ARG_HELP_SHORT
Definition: command.h:31
#define _(s)
const wxChar *const kicadTraceKeyEvent
Flag to enable wxKeyEvent debug tracing.
static CLI::EXPORT_PCB_POS_COMMAND exportPcbPosCmd
Definition: kicad_cli.cpp:133
static CLI::EXPORT_SCH_PLOT_COMMAND exportSchSvgCmd
Definition: kicad_cli.cpp:147
PGM_KICAD & PgmTop()
Definition: kicad_cli.cpp:110
static CLI::EXPORT_PCB_PDF_COMMAND exportPcbPdfCmd
Definition: kicad_cli.cpp:132
static CLI::EXPORT_PCB_DXF_COMMAND exportPcbDxfCmd
Definition: kicad_cli.cpp:129
static CLI::EXPORT_SCH_COMMAND exportSchCmd
Definition: kicad_cli.cpp:138
static CLI::EXPORT_SCH_PLOT_COMMAND exportSchHpglCmd
Definition: kicad_cli.cpp:144
static CLI::FP_EXPORT_SVG_COMMAND fpExportSvgCmd
Definition: kicad_cli.cpp:150
static CLI::SYM_UPGRADE_COMMAND symUpgradeCmd
Definition: kicad_cli.cpp:155
static CLI::FP_EXPORT_COMMAND fpExportCmd
Definition: kicad_cli.cpp:149
static CLI::FP_UPGRADE_COMMAND fpUpgradeCmd
Definition: kicad_cli.cpp:151
static void printHelp(argparse::ArgumentParser &argParser)
Definition: kicad_cli.cpp:263
static CLI::EXPORT_SCH_PLOT_COMMAND exportSchDxfCmd
Definition: kicad_cli.cpp:143
static CLI::EXPORT_PCB_GERBER_COMMAND exportPcbGerberCmd
Definition: kicad_cli.cpp:134
static CLI::EXPORT_PCB_COMMAND exportPcbCmd
Definition: kicad_cli.cpp:136
static CLI::EXPORT_SCH_NETLIST_COMMAND exportSchNetlistCmd
Definition: kicad_cli.cpp:142
static CLI::EXPORT_PCB_DRILL_COMMAND exportPcbDrillCmd
Definition: kicad_cli.cpp:128
static CLI::SYM_COMMAND symCmd
Definition: kicad_cli.cpp:152
PROJECT & Prj()
Definition: kicad_cli.cpp:558
static CLI::EXPORT_PCB_GERBERS_COMMAND exportPcbGerbersCmd
Definition: kicad_cli.cpp:135
static CLI::EXPORT_SCH_PLOT_COMMAND exportSchPdfCmd
Definition: kicad_cli.cpp:145
static CLI::EXPORT_PCB_STEP_COMMAND exportPcbStepCmd
Definition: kicad_cli.cpp:130
static CLI::EXPORT_PCB_SVG_COMMAND exportPcbSvgCmd
Definition: kicad_cli.cpp:131
static PGM_KICAD program
Definition: kicad_cli.cpp:94
static CLI::EXPORT_SCH_PYTHONBOM_COMMAND exportSchPythonBomCmd
Definition: kicad_cli.cpp:141
static CLI::SCH_COMMAND schCmd
Definition: kicad_cli.cpp:139
static CLI::PCB_COMMAND pcbCmd
Definition: kicad_cli.cpp:137
static std::vector< COMMAND_ENTRY > commandStack
Definition: kicad_cli.cpp:159
static CLI::SYM_EXPORT_COMMAND symExportCmd
Definition: kicad_cli.cpp:153
static CLI::EXPORT_SCH_PLOT_COMMAND exportSchPostscriptCmd
Definition: kicad_cli.cpp:146
static CLI::SYM_EXPORT_SVG_COMMAND symExportSvgCmd
Definition: kicad_cli.cpp:154
static COMMAND_ENTRY * recurseArgParserSubCommandUsed(argparse::ArgumentParser &aArgParser, COMMAND_ENTRY &aEntry)
Definition: kicad_cli.cpp:241
static CLI::EXPORT_SCH_BOM_COMMAND exportSchBomCmd
Definition: kicad_cli.cpp:140
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: kicad_cli.cpp:97
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
Definition: kicad_cli.cpp:83
static CLI::VERSION_COMMAND versionCmd
Definition: kicad_cli.cpp:156
PGM_BASE * PgmOrNull()
similar to PGM_BASE& Pgm(), but return a reference that can be nullptr when running a shared lib from...
Definition: kicad_cli.cpp:104
static void recurseArgParserBuild(argparse::ArgumentParser &aArgParser, COMMAND_ENTRY &aEntry)
Definition: kicad_cli.cpp:230
static CLI::FP_COMMAND fpCmd
Definition: kicad_cli.cpp:148
#define KFCTL_CPP_PROJECT_SUITE
Running under C++ project mgr, possibly with others.
Definition: kiway.h:159
KIWAY Kiway
#define KFCTL_CLI
Running as CLI app.
Definition: kiway.h:160
This file contains miscellaneous commonly used macros and functions.
static wxString FROM_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:110
static const int ERR_ARGS
Definition: exit_codes.h:31
static const int AVOID_CLOSING
Definition: exit_codes.h:28
bool Init()
Perform application-specific initialization tasks.
Definition: gtk/app.cpp:40
void Init()
Perform environment initialization tasks.
std::vector< FAB_LAYER_COLOR > dummy
Not publicly visible because most of the action is in PGM_KICAD these days.
Definition: kicad_cli.cpp:456
int OnExit() override
Definition: kicad_cli.cpp:479
bool OnInit() override
Definition: kicad_cli.cpp:464
int FilterEvent(wxEvent &aEvent) override
Definition: kicad_cli.cpp:505
int OnRun() override
Definition: kicad_cli.cpp:491
void End()
Definition: bin_mod.cpp:50
void Init()
Definition: bin_mod.cpp:38
void InitSettings(APP_SETTINGS_BASE *aPtr)
Takes ownership of a new application settings object.
Definition: bin_mod.h:53
Definition: kicad_cli.cpp:117
COMMAND_ENTRY(CLI::COMMAND *aHandler)
Definition: kicad_cli.cpp:122
COMMAND_ENTRY(CLI::COMMAND *aHandler, std::vector< COMMAND_ENTRY > aSub)
Definition: kicad_cli.cpp:123
CLI::COMMAND * handler
Definition: kicad_cli.cpp:118
std::vector< COMMAND_ENTRY > subCommands
Definition: kicad_cli.cpp:120
System directories search utilities.
wxString dump(const wxArrayString &aArray)
Debug helper for printing wxArrayString contents.
wxLogTrace helper definitions.