KiCad PCB EDA Suite
Loading...
Searching...
No Matches
command_mergetool.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.html
19 * or you may search the http://www.gnu.org website for the version 3 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include "command_mergetool.h"
25
26#include <cli/exit_codes.h>
28#include <kiface_base.h>
29#include <kiway.h>
30#include <paths.h>
31#include <string_utils.h>
32
33#include <wx/crt.h>
34#include <wx/filename.h>
35#include <wx/utils.h>
36
37
38#define ARG_ANCESTOR "ancestor"
39#define ARG_OURS "ours"
40#define ARG_THEIRS "theirs"
41#define ARG_OUTPUT_F "--output"
42
43
47static int translateExitCode( int aKicadExit )
48{
49 using namespace CLI::EXIT_CODES;
50
51 switch( aKicadExit )
52 {
53 case SUCCESS: return 0;
54 case ERR_RC_VIOLATIONS: return 2; // unresolved conflicts
56 case ERR_INVALID_OUTPUT_CONFLICT: return 3; // I/O or parse error
57 default: return aKicadExit;
58 }
59}
60
61
63{
64 switch( aKind )
65 {
70 return true;
71
72 default:
73 return false;
74 }
75}
76
77
79 COMMAND( "mergetool" )
80{
81 m_argParser.add_description(
82 UTF8STDSTR( _( "Three-way merge driver for `git mergetool`. Detects PCB vs "
83 "schematic vs library item from the output extension, opens "
84 "the resolution dialog in the GUI kicad binary for any "
85 "unresolved conflicts where available, "
86 "and writes the merged file." ) ) );
87
88 m_argParser.add_argument( ARG_ANCESTOR )
89 .help( UTF8STDSTR( _( "Common-ancestor file (.kicad_pcb, .kicad_sch, "
90 ".kicad_sym, or .kicad_mod)" ) ) )
91 .metavar( "ANCESTOR" );
92
93 m_argParser.add_argument( ARG_OURS )
94 .help( UTF8STDSTR( _( "'Ours' file" ) ) )
95 .metavar( "OURS" );
96
97 m_argParser.add_argument( ARG_THEIRS )
98 .help( UTF8STDSTR( _( "'Theirs' file" ) ) )
99 .metavar( "THEIRS" );
100
101 m_argParser.add_argument( "-o", ARG_OUTPUT_F )
102 .required()
103 .help( UTF8STDSTR( _( "Output path; extension picks the document type" ) ) )
104 .metavar( "PATH" );
105}
106
107
109{
110 const wxString ancestor = From_UTF8( m_argParser.get<std::string>( ARG_ANCESTOR ).c_str() );
111 const wxString ours = From_UTF8( m_argParser.get<std::string>( ARG_OURS ).c_str() );
112 const wxString theirs = From_UTF8( m_argParser.get<std::string>( ARG_THEIRS ).c_str() );
113 const wxString output = From_UTF8( m_argParser.get<std::string>( ARG_OUTPUT_F ).c_str() );
114
115 if( output.IsEmpty() )
116 {
117 wxFprintf( stderr, _( "--output is required\n" ) );
119 }
120
122
123 if( !supportsMergetoolKind( kind ) )
124 {
125 wxFprintf( stderr,
126 _( "Unsupported output extension '%s'. "
127 "Expected .kicad_pcb, .kicad_sch, .kicad_sym, or .kicad_mod\n" ),
128 output );
129 return EXIT_CODES::ERR_INVALID_INPUT_FILE; // contract code 3 — bad input
130 }
131
132 // The conflict-resolution dialog needs a GUI, which kicad-cli doesn't
133 // provide. Re-exec the main `kicad` binary in --mergetool mode so the
134 // user gets the interactive dialog. This is the documented Phase 8
135 // contract for `git mergetool`.
136 const wxString kicadBinPath = PATHS::ResolveSiblingExecutable( wxT( "kicad" ) );
137
138 if( kicadBinPath.IsEmpty() )
139 {
140 wxFprintf( stderr,
141 _( "Cannot find the main kicad binary alongside kicad-cli.\n" ) );
142 return 4; // contract code 4 — initialization failure
143 }
144
145 // Pass argv as an array so paths containing spaces or quotes aren't
146 // mis-parsed by the string-form wxExecute's shell-style tokenizer.
147 // wxExecute's array form needs c_str()-backed pointers, so we hold
148 // wxCharBuffer / wxScopedCharBuffer locals to keep them alive.
149 const wxScopedCharBuffer args[] = {
150 kicadBinPath.utf8_str(),
151 wxScopedCharBuffer::CreateNonOwned( "--mergetool" ),
152 ancestor.utf8_str(),
153 ours.utf8_str(),
154 theirs.utf8_str(),
155 output.utf8_str()
156 };
157
158 const char* argv[] = { args[0].data(), args[1].data(), args[2].data(),
159 args[3].data(), args[4].data(), args[5].data(),
160 nullptr };
161
162 const long rc = wxExecute( const_cast<char**>( argv ), wxEXEC_SYNC );
163
164 if( rc < 0 )
165 {
166 wxFprintf( stderr, _( "Failed to launch '%s'\n" ), kicadBinPath );
167 return 4;
168 }
169
170 return translateExitCode( static_cast<int>( rc ) );
171}
argparse::ArgumentParser m_argParser
Definition command.h:113
COMMAND(const std::string &aName)
Define a new COMMAND instance.
Definition command.cpp:30
int doPerform(KIWAY &aKiway) override
The internal handler that should be overloaded to implement command specific processing and work.
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:311
static wxString ResolveSiblingExecutable(const wxString &aBaseName)
Resolve a sibling executable alongside the running process.
Definition paths.cpp:717
#define UTF8STDSTR(s)
Definition command.h:27
#define ARG_ANCESTOR
#define ARG_THEIRS
#define ARG_OUTPUT_F
#define ARG_OURS
static bool supportsMergetoolKind(KICAD_DIFF::DOC_KIND aKind)
static int translateExitCode(int aKicadExit)
Map kicad-side exit codes to the Phase 8 mergetool contract documented in the header.
#define _(s)
static const int ERR_ARGS
Definition exit_codes.h:31
static const int ERR_RC_VIOLATIONS
Rules check violation count was greater than 0.
Definition exit_codes.h:37
static const int ERR_INVALID_INPUT_FILE
Definition exit_codes.h:33
static const int SUCCESS
Definition exit_codes.h:29
static const int ERR_INVALID_OUTPUT_CONFLICT
Definition exit_codes.h:34
DOC_KIND DocKindFromExtension(const wxString &aPath)
Map a path's extension to a DOC_KIND (.kicad_pcb -> PCB, .kicad_sch -> SCH, .kicad_sym -> SYM_LIB,...
DOC_KIND
Document type a diff/merge entry point should route to, derived from a file path's extension.
wxString From_UTF8(const char *cstring)
nlohmann::json output