From b802a3e776372119e8a52d8c793b1b77b6165658 Mon Sep 17 00:00:00 2001 From: Jon Evans Date: Sun, 19 Apr 2020 14:28:36 -0400 Subject: [PATCH] Add command-line option to generate netlist and exit --- common/single_top.cpp | 71 +++++++++++++++++++----------------- eeschema/files-io.cpp | 12 ++++++ eeschema/sch_edit_frame.cpp | 14 +++++++ eeschema/sch_edit_frame.h | 7 ++++ include/kiway_player.h | 13 +++++++ qa/eeschema/test_netlists.py | 0 6 files changed, 83 insertions(+), 34 deletions(-) create mode 100644 qa/eeschema/test_netlists.py diff --git a/common/single_top.cpp b/common/single_top.cpp index 475e0912e1..10b024a7b5 100644 --- a/common/single_top.cpp +++ b/common/single_top.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -316,10 +317,16 @@ bool PGM_SINGLE_TOP::OnPgmInit() Kiway.set_kiface( KIWAY::KifaceType( TOP_FRAME ), kiface ); #endif - // Open project or file specified on the command line: - int argc = App().argc; + static const wxCmdLineEntryDesc desc[] = { + { wxCMD_LINE_OPTION, "f", "frame", _( "Frame to load" ) }, + { wxCMD_LINE_PARAM, nullptr, nullptr, _( "File to load" ), wxCMD_LINE_VAL_STRING, + wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL }, + { wxCMD_LINE_NONE } + }; - int args_offset = 1; + wxCmdLineParser parser( App().argc, App().argv ); + parser.SetDesc( desc ); + parser.Parse( false ); FRAME_T appType = TOP_FRAME; @@ -333,28 +340,22 @@ bool PGM_SINGLE_TOP::OnPgmInit() { wxT( "" ), FRAME_T_COUNT } }; - if( argc > 2 ) + wxString frameName; + + if( parser.Found( "frame", &frameName ) ) { - if( App().argv[1] == "--frame" ) + appType = FRAME_T_COUNT; + + for( const auto& it : frameTypes ) { - wxString appName = App().argv[2]; - appType = FRAME_T_COUNT; + if( it.name == frameName ) + appType = it.type; + } - for( int i = 0; frameTypes[i].type != FRAME_T_COUNT; i++ ) - { - const auto& frame = frameTypes[i]; - if(frame.name == appName) - { - appType = frame.type; - } - } - args_offset += 2; - - if( appType == FRAME_T_COUNT ) - { - wxLogError( wxT( "Unknown frame: %s" ), appName ); - return false; - } + if( appType == FRAME_T_COUNT ) + { + wxLogError( wxT( "Unknown frame: %s" ), frameName ); + return false; } } @@ -368,8 +369,14 @@ bool PGM_SINGLE_TOP::OnPgmInit() App().SetTopWindow( frame ); // wxApp gets a face. + // Individual frames may provide additional option/switch processing, but for compatibility, + // any positional arguments are treated as a list of files to pass to OpenProjectFiles + frame->ParseArgs( parser ); - if( argc > args_offset ) + // Now after the frame processing, the rest of the positional args are files + std::vector fileArgs; + + if( parser.GetParamCount() ) { /* gerbview handles multiple project data files, i.e. gerber files on @@ -380,33 +387,29 @@ bool PGM_SINGLE_TOP::OnPgmInit() launcher. */ - std::vector argSet; - - for( int i = args_offset; i < argc; ++i ) - { - argSet.push_back( App().argv[i] ); - } + for( size_t i = 0; i < parser.GetParamCount(); i++ ) + fileArgs.push_back( parser.GetParam( i ) ); // special attention to a single argument: argv[1] (==argSet[0]) - if( argc == args_offset + 1 ) + if( fileArgs.size() == 1 ) { - wxFileName argv1( argSet[0] ); + wxFileName argv1( fileArgs[0] ); #if defined(PGM_DATA_FILE_EXT) // PGM_DATA_FILE_EXT, if present, may be different for each compile, // it may come from CMake on the compiler command line, but often does not. - // This facillity is mostly useful for those program modules + // This facility is mostly useful for those program modules // supporting a single argv[1]. if( !argv1.GetExt() ) argv1.SetExt( wxT( PGM_DATA_FILE_EXT ) ); #endif argv1.MakeAbsolute(); - argSet[0] = argv1.GetFullPath(); + fileArgs[0] = argv1.GetFullPath(); } // Use the KIWAY_PLAYER::OpenProjectFiles() API function: - if( !frame->OpenProjectFiles( argSet ) ) + if( !frame->OpenProjectFiles( fileArgs ) ) { // OpenProjectFiles() API asks that it report failure to the UI. // Nothing further to say here. diff --git a/eeschema/files-io.cpp b/eeschema/files-io.cpp index 01b918ffe0..22ef0102e5 100644 --- a/eeschema/files-io.cpp +++ b/eeschema/files-io.cpp @@ -52,6 +52,7 @@ #include #include #include +#include bool SCH_EDIT_FRAME::SaveEEFile( SCH_SCREEN* aScreen, bool aSaveUnderNewName, bool aCreateBackupFile ) @@ -445,6 +446,17 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, in UpdateTitle(); + // If requested, generate a netlist and exit immediately. + // NOTE: This is intended as a developer-only feature for now, and can be removed in lieu of + // Python scripting once that is possible. + if( m_generateNetlistAndExit ) + { + wxLogDebug( wxT( "Writing netlist to %s and exiting..." ), m_netlistFilename ); + NETLIST_OBJECT_LIST* netlist = CreateNetlist( false, false ); + WriteNetListFile( netlist, NET_TYPE_PCBNEW, m_netlistFilename, 0, nullptr ); + Close( false ); + } + return true; } diff --git a/eeschema/sch_edit_frame.cpp b/eeschema/sch_edit_frame.cpp index 65c08376be..f3a36e71f7 100644 --- a/eeschema/sch_edit_frame.cpp +++ b/eeschema/sch_edit_frame.cpp @@ -69,6 +69,7 @@ #include #include #include +#include #include @@ -226,6 +227,9 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ): m_findReplaceDialog = nullptr; m_findReplaceStatusPopup = nullptr; + m_generateNetlistAndExit = false; + m_netlistFilename = wxEmptyString; + SetSpiceAdjustPassiveValues( false ); // Give an icon @@ -790,6 +794,16 @@ void SCH_EDIT_FRAME::LoadProject() } +void SCH_EDIT_FRAME::ParseArgs( wxCmdLineParser& aParser ) +{ + aParser.AddOption( "n", "netlist" ); + aParser.Parse(); + + if( aParser.Found( "netlist", &m_netlistFilename ) ) + m_generateNetlistAndExit = true; +} + + void SCH_EDIT_FRAME::OnOpenPcbnew( wxCommandEvent& event ) { wxFileName kicad_board = Prj().AbsolutePath( g_RootSheet->GetScreen()->GetFileName() ); diff --git a/eeschema/sch_edit_frame.h b/eeschema/sch_edit_frame.h index 1d450b3908..7ec9043297 100644 --- a/eeschema/sch_edit_frame.h +++ b/eeschema/sch_edit_frame.h @@ -149,6 +149,11 @@ private: static PINSHEETLABEL_SHAPE m_lastSheetPinType; ///< Last sheet pin type. + // NOTE: This is a developer-only feature and can be replaced by appropriate Python + // functionality once that is possible. + bool m_generateNetlistAndExit; ///< For command-line netlist generation + wxString m_netlistFilename; + protected: /** * Save the schematic files that have been modified and not yet saved. @@ -576,6 +581,8 @@ public: bool OpenProjectFiles( const std::vector& aFileSet, int aCtl = 0 ) override; + void ParseArgs( wxCmdLineParser& aParser ) override; + /** * Import a KiCad schematic into the current sheet. * diff --git a/include/kiway_player.h b/include/kiway_player.h index dce1929c74..80477aefc2 100644 --- a/include/kiway_player.h +++ b/include/kiway_player.h @@ -127,6 +127,19 @@ public: return false; } + /** + * Handles command-line arguments in a frame-specific way. + * The given argument parser has already been initialized with the command line and any + * options/switches that are handled by the top-level launcher before passing control to + * the child frame. + * + * @param aParser is the argument parser created by the top-level launcher. + */ + virtual void ParseArgs( wxCmdLineParser& aParser ) + { + WXUNUSED( aParser ); + } + /** * Function ShowModal diff --git a/qa/eeschema/test_netlists.py b/qa/eeschema/test_netlists.py new file mode 100644 index 0000000000..e69de29bb2