33#include <wx/filename.h>
35#include <wx/tokenzr.h>
44 static const wxString kicadEntries[] = {
45 wxS(
".history/" ), wxS(
"*-backups/" ), wxS(
"_autosave-*" ),
46 wxS(
"fp-info-cache" ), wxS(
"~*.lck" ), wxS(
"*.kicad_prl" ),
49 wxFileName ignoreFile( aProjectPath, wxS(
".gitignore" ) );
50 std::set<wxString> existing;
51 bool fileExists = ignoreFile.FileExists();
52 bool hasTrailingNewline =
true;
56 wxFFile in( ignoreFile.GetFullPath(), wxT(
"r" ) );
59 if( !in.IsOpened() || !in.ReadAll( &contents ) )
62 hasTrailingNewline = contents.empty() || contents.EndsWith( wxS(
"\n" ) );
64 wxStringTokenizer tok( contents, wxS(
"\n" ) );
66 while( tok.HasMoreTokens() )
68 wxString line = tok.GetNextToken();
69 line.Trim().Trim(
false );
71 if( !line.empty() && !line.StartsWith( wxS(
"#" ) ) )
72 existing.insert( line );
78 for(
const wxString& entry : kicadEntries )
80 if( existing.find( entry ) == existing.end() )
81 missing += entry + wxS(
"\n" );
87 wxFFile out( ignoreFile.GetFullPath(), wxT(
"a" ) );
93 out.Write( wxS(
"# KiCad-generated files and directories.\n" ) );
94 else if( !hasTrailingNewline )
95 out.Write( wxS(
"\n" ) );
111 static const std::pair<wxString, wxString> kicadEntries[] = {
112 { wxS(
"*.kicad_pcb" ), wxS(
"merge=kicad-pcb" ) },
113 { wxS(
"*.kicad_sch" ), wxS(
"merge=kicad-sch" ) },
114 { wxS(
"*.kicad_sym" ), wxS(
"merge=kicad-sym-lib" ) },
115 { wxS(
"*.kicad_mod" ), wxS(
"merge=kicad-fp" ) },
118 wxFileName attrFile( aProjectPath, wxS(
".gitattributes" ) );
121 std::set<wxString> existingPatterns;
122 bool fileExists = attrFile.FileExists();
123 bool hasTrailingNewline =
true;
127 wxFFile in( attrFile.GetFullPath(), wxT(
"r" ) );
130 if( !in.IsOpened() || !in.ReadAll( &contents ) )
133 hasTrailingNewline = contents.empty() || contents.EndsWith( wxS(
"\n" ) );
135 wxStringTokenizer tok( contents, wxS(
"\n" ) );
137 while( tok.HasMoreTokens() )
139 wxString line = tok.GetNextToken();
140 line.Trim().Trim(
false );
142 if( line.empty() || line.StartsWith( wxS(
"#" ) ) )
146 wxString pattern = line.BeforeFirst(
' ' );
147 pattern = pattern.BeforeFirst(
'\t' );
149 if( !pattern.empty() )
150 existingPatterns.insert( pattern );
156 for(
const auto& [glob, attr] : kicadEntries )
158 if( existingPatterns.find( glob ) == existingPatterns.end() )
159 missing += glob + wxS(
" " ) + attr + wxS(
"\n" );
162 if( missing.empty() )
165 wxFFile out( attrFile.GetFullPath(), wxT(
"a" ) );
167 if( !out.IsOpened() )
171 out.Write( wxS(
"# KiCad design files use custom merge drivers.\n" ) );
172 else if( !hasTrailingNewline )
173 out.Write( wxS(
"\n" ) );
175 out.Write( missing );
193 git_config_entry* entry =
nullptr;
194 int result = git_config_get_entry( &entry, aConfig, aKey );
197 if(
result == 0 && entry )
199 wxLogTrace(
traceGit,
"Config key '%s' already set; leaving alone", aKey );
203 std::string val( aValue.ToUTF8() );
205 if( git_config_set_string( aConfig, aKey, val.c_str() ) != 0 )
207 wxLogTrace(
traceGit,
"git_config_set_string('%s') failed: %s",
225 if( cliPath.IsEmpty() )
228 "kicad-cli not found next to running binary; skipping merge driver "
229 "config (libgit2 in-process driver still works)." );
233 git_repository* repo =
nullptr;
235 if( git_repository_open( &repo, aProjectPath.ToUTF8() ) != 0 )
237 wxLogTrace(
traceGit,
"git_repository_open failed: %s",
244 git_config*
config =
nullptr;
246 if( git_repository_config( &
config, repo ) != 0 )
248 wxLogTrace(
traceGit,
"git_repository_config failed: %s",
268 const char* driverKey;
269 const char* humanName;
270 const char* cliCommand;
273 static const DRIVER_ENTRY drivers[] = {
274 {
"merge.kicad-pcb.name",
"merge.kicad-pcb.driver",
"KiCad PCB merge driver",
275 "git-mergedriver --kind pcb \"%O\" \"%A\" \"%B\" --output \"%A\"" },
276 {
"merge.kicad-sch.name",
"merge.kicad-sch.driver",
"KiCad schematic merge driver",
277 "git-mergedriver --kind sch \"%O\" \"%A\" \"%B\" --output \"%A\"" },
278 {
"merge.kicad-sym-lib.name",
"merge.kicad-sym-lib.driver",
279 "KiCad symbol library merge driver",
280 "git-mergedriver --kind sym \"%O\" \"%A\" \"%B\" --output \"%A\"" },
281 {
"merge.kicad-fp.name",
"merge.kicad-fp.driver",
"KiCad footprint merge driver",
282 "git-mergedriver --kind fp \"%O\" \"%A\" \"%B\" --output \"%A\"" }
285 for(
const DRIVER_ENTRY& d : drivers )
289 wxString cmd = wxT(
"\"" ) + cliPath + wxT(
"\" " ) + wxString::FromUTF8( d.cliCommand );
296 wxString
mergetoolCmd = wxT(
"\"" ) + cliPath + wxT(
"\" mergetool "
297 "\"$BASE\" \"$LOCAL\" \"$REMOTE\" "
298 "--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()
void UpdateProgress(int aCurrent, int aTotal, const wxString &aMessage) override
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.
void ReportProgress(int aCurrent, int aTotal, const wxString &aMessage)
static wxString GetLastGitError()
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.