35#include <wx/filename.h>
37#include <wx/tokenzr.h>
44 wxFileName ignoreFile( aProjectPath, wxS(
".gitignore" ) );
46 if( ignoreFile.FileExists() )
52 if( !out.Create( ignoreFile.GetFullPath(),
false ) )
55 wxString contents = wxS(
"# KiCad-generated files and directories.\n" );
58 contents += entry + wxS(
"\n" );
61 if( !out.Write( contents ) || !out.Close() )
64 wxRemoveFile( ignoreFile.GetFullPath() );
79 static const std::pair<wxString, wxString> kicadEntries[] = {
80 { wxS(
"*.kicad_pcb" ), wxS(
"merge=kicad-pcb" ) },
81 { wxS(
"*.kicad_sch" ), wxS(
"merge=kicad-sch" ) },
82 { wxS(
"*.kicad_sym" ), wxS(
"merge=kicad-sym-lib" ) },
83 { wxS(
"*.kicad_mod" ), wxS(
"merge=kicad-fp" ) },
86 wxFileName attrFile( aProjectPath, wxS(
".gitattributes" ) );
89 std::set<wxString> existingPatterns;
90 bool fileExists = attrFile.FileExists();
91 bool hasTrailingNewline =
true;
95 wxFFile in( attrFile.GetFullPath(), wxT(
"r" ) );
98 if( !in.IsOpened() || !in.ReadAll( &contents ) )
101 hasTrailingNewline = contents.empty() || contents.EndsWith( wxS(
"\n" ) );
103 wxStringTokenizer tok( contents, wxS(
"\n" ) );
105 while( tok.HasMoreTokens() )
107 wxString line = tok.GetNextToken();
108 line.Trim().Trim(
false );
110 if( line.empty() || line.StartsWith( wxS(
"#" ) ) )
114 wxString pattern = line.BeforeFirst(
' ' );
115 pattern = pattern.BeforeFirst(
'\t' );
117 if( !pattern.empty() )
118 existingPatterns.insert( pattern );
124 for(
const auto& [glob, attr] : kicadEntries )
126 if( existingPatterns.find( glob ) == existingPatterns.end() )
127 missing += glob + wxS(
" " ) + attr + wxS(
"\n" );
130 if( missing.empty() )
133 wxFFile out( attrFile.GetFullPath(), wxT(
"a" ) );
135 if( !out.IsOpened() )
139 out.Write( wxS(
"# KiCad design files use custom merge drivers.\n" ) );
140 else if( !hasTrailingNewline )
141 out.Write( wxS(
"\n" ) );
143 out.Write( missing );
161 git_config_entry* entry =
nullptr;
162 int result = git_config_get_entry( &entry, aConfig, aKey );
165 if(
result == 0 && entry )
167 wxLogTrace(
traceGit,
"Config key '%s' already set; leaving alone", aKey );
171 std::string val( aValue.ToUTF8() );
173 if( git_config_set_string( aConfig, aKey, val.c_str() ) != 0 )
175 wxLogTrace(
traceGit,
"git_config_set_string('%s') failed: %s",
193 if( cliPath.IsEmpty() )
196 "kicad-cli not found next to running binary; skipping merge driver "
197 "config (libgit2 in-process driver still works)." );
203 if( git_repository_open( &repo, aProjectPath.ToUTF8() ) != 0 )
205 wxLogTrace(
traceGit,
"git_repository_open failed: %s",
212 git_config*
config =
nullptr;
214 if( git_repository_config( &
config, repo ) != 0 )
216 wxLogTrace(
traceGit,
"git_repository_config failed: %s",
236 const char* driverKey;
237 const char* humanName;
238 const char* cliCommand;
241 static const DRIVER_ENTRY drivers[] = {
242 {
"merge.kicad-pcb.name",
"merge.kicad-pcb.driver",
"KiCad PCB merge driver",
243 "git-mergedriver --kind pcb \"%O\" \"%A\" \"%B\" --output \"%A\"" },
244 {
"merge.kicad-sch.name",
"merge.kicad-sch.driver",
"KiCad schematic merge driver",
245 "git-mergedriver --kind sch \"%O\" \"%A\" \"%B\" --output \"%A\"" },
246 {
"merge.kicad-sym-lib.name",
"merge.kicad-sym-lib.driver",
247 "KiCad symbol library merge driver",
248 "git-mergedriver --kind sym \"%O\" \"%A\" \"%B\" --output \"%A\"" },
249 {
"merge.kicad-fp.name",
"merge.kicad-fp.driver",
"KiCad footprint merge driver",
250 "git-mergedriver --kind fp \"%O\" \"%A\" \"%B\" --output \"%A\"" }
253 for(
const DRIVER_ENTRY& d : drivers )
257 wxString cmd = wxT(
"\"" ) + cliPath + wxT(
"\" " ) + wxString::FromUTF8( d.cliCommand );
264 wxString
mergetoolCmd = wxT(
"\"" ) + cliPath + wxT(
"\" mergetool "
265 "\"$BASE\" \"$LOCAL\" \"$REMOTE\" "
266 "--output \"$MERGED\"" );
virtual InitResult InitializeRepository(GIT_INIT_HANDLER *aHandler, const wxString &aPath)=0
virtual bool IsRepository(GIT_INIT_HANDLER *aHandler, const wxString &aPath)=0
virtual bool SetupRemote(GIT_INIT_HANDLER *aHandler, const RemoteConfig &aConfig)=0
bool IsRepository(const wxString &aPath)
Check if a directory is already a git repository.
virtual ~GIT_INIT_HANDLER()
GIT_INIT_HANDLER(KIGIT_COMMON *aCommon)
InitResult InitializeRepository(const wxString &aPath)
Initialize a new git repository in the specified directory.
bool SetupRemote(const RemoteConfig &aConfig)
Set up a remote for the repository.
static const std::vector< wxString > & TransientGitIgnorePatterns()
Shared patterns for new .gitignore files and the untracked-file filter.
The project's git session.
static wxString GetLastGitError()
libgit2's last message, without credentials from any URL it quotes, so it is safe to show or trace.
KIGIT_REPO_MIXIN(KIGIT_COMMON *aCommon)
static wxString ResolveSiblingExecutable(const wxString &aBaseName)
Resolve a sibling executable alongside the running process.
GIT_BACKEND * GetGitBackend()
static void ensureProjectGitignore(const wxString &aProjectPath)
static wxString resolveKicadCliPath()
static void ensureProjectGitattributes(const wxString &aProjectPath)
void ApplyKicadGitConventions(const wxString &aProjectPath)
Apply KiCad's standard repo conventions to a project directory:
static void ensureMergeDriverConfig(const wxString &aProjectPath)
static bool setConfigIfMissing(git_config *aConfig, const char *aKey, const wxString &aValue)
APIEXPORT void ApplyKicadGitConventions(const wxString &aProjectPath)
Apply KiCad's standard repo conventions to a project directory:
const wxChar *const traceGit
Flag to enable Git debugging output.
static CLI::MERGETOOL_COMMAND mergetoolCmd
std::unique_ptr< git_repository, decltype([](git_repository *aRepo) { git_repository_free(aRepo); })> GitRepositoryPtr
A unique pointer for git_repository objects with automatic cleanup.
std::unique_ptr< git_config, decltype([](git_config *aConfig) { git_config_free(aConfig); })> GitConfigPtr
A unique pointer for git_config objects with automatic cleanup.
std::unique_ptr< git_config_entry, decltype([](git_config_entry *aEntry) { git_config_entry_free(aEntry); })> GitConfigEntryPtr
A unique pointer for git_config_entry objects with automatic cleanup.
wxString result
Test unit parsing edge cases and error handling.
wxLogTrace helper definitions.